|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics;
[CompilerTrait(CompilerFeature.Unsafe)]
public sealed class UnsafeEvolutionTests : CompilingTestBase
{
/// <param name="expectedUnsafeSymbols">See <see cref="VerifyRequiresUnsafeAttribute"/>.</param>
/// <param name="expectedSafeSymbols">See <see cref="VerifyRequiresUnsafeAttribute"/>.</param>
private void CompileAndVerifyUnsafe(
string lib,
string caller,
object[] expectedUnsafeSymbols,
object[] expectedSafeSymbols,
DiagnosticDescription[] expectedDiagnostics,
ReadOnlySpan<string> additionalSources = default,
Verification verify = default,
CallerUnsafeMode expectedUnsafeMode = CallerUnsafeMode.Explicit,
object[]? expectedNoAttributeInSource = null,
object[]? expectedNoAttributeUnderLegacyRules = null,
object[]? skipSymbolsInSource = null,
CSharpParseOptions? parseOptions = null,
CSharpCompilationOptions? optionsDll = null,
TargetFramework targetFramework = TargetFramework.Standard,
DiagnosticDescription[]? expectedDiagnosticsWhenReferencingLegacyLib = null,
DiagnosticDescription[]? expectedDiagnosticsForLegacyCaller = null)
{
optionsDll ??= TestOptions.UnsafeReleaseDll;
var optionsExe = optionsDll.WithOutputKind(OutputKind.ConsoleApplication);
Assert.False(optionsDll.UseUpdatedMemorySafetyRules);
CreateCompilation([lib, caller, .. additionalSources],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
var libUpdated = CompileAndVerify([lib, .. additionalSources],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsDll.WithUpdatedMemorySafetyRules(),
verify: verify,
symbolValidator: symbolValidator)
.VerifyDiagnostics();
var libUpdatedRefs = new MetadataReference[] { libUpdated.GetImageReference(), libUpdated.Compilation.ToMetadataReference() };
foreach (var libUpdatedRef in libUpdatedRefs)
{
var libAssemblySymbol = CreateCompilation(caller, [libUpdatedRef],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics)
.GetReferencedAssemblySymbol(libUpdatedRef);
symbolValidator(libAssemblySymbol.Modules.Single());
// Updated-rules library referenced by legacy-rules caller.
CreateCompilation(caller, [libUpdatedRef],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsExe.AddSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules), ReportDiagnostic.Suppress))
.VerifyDiagnostics(expectedDiagnosticsForLegacyCaller ?? []);
}
var libLegacy = CompileAndVerify([lib, .. additionalSources],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsDll.AddSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules), ReportDiagnostic.Suppress),
verify: verify,
symbolValidator: module =>
{
VerifyMemorySafetyRulesAttribute(module, includesAttributeDefinition: false, includesAttributeUse: false);
VerifyRequiresUnsafeAttribute(
module,
expectedUnsafeSymbols: expectedUnsafeSymbols,
expectedSafeSymbols: expectedSafeSymbols,
expectedNoAttributeInSource: expectedNoAttributeInSource,
expectedNoAttribute: expectedNoAttributeUnderLegacyRules,
expectedUnsafeMode: CallerUnsafeMode.None);
})
.VerifyDiagnostics()
.GetImageReference();
CreateCompilation(caller, [libLegacy],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsExe.WithUpdatedMemorySafetyRules())
.VerifyEmitDiagnostics(expectedDiagnosticsWhenReferencingLegacyLib ?? []);
// Legacy-rules library referenced by legacy-rules caller.
CreateCompilation(caller, [libLegacy],
targetFramework: targetFramework,
parseOptions: parseOptions,
options: optionsExe.AddSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules), ReportDiagnostic.Suppress))
.VerifyEmitDiagnostics(expectedDiagnosticsForLegacyCaller ?? []);
void symbolValidator(ModuleSymbol module)
{
var isSource = module is SourceModuleSymbol;
VerifyMemorySafetyRulesAttribute(
module,
includesAttributeDefinition: !isSource,
includesAttributeUse: !isSource,
isSynthesized: isSource ? null : true);
VerifyRequiresUnsafeAttribute(
module,
expectedUnsafeSymbols: exceptSymbolsSkippedInSource(expectedUnsafeSymbols),
expectedSafeSymbols: exceptSymbolsSkippedInSource(expectedSafeSymbols),
expectedNoAttributeInSource: exceptSymbolsSkippedInSource(expectedNoAttributeInSource),
expectedUnsafeMode: expectedUnsafeMode);
[return: NotNullIfNotNull(nameof(original))]
object[]? exceptSymbolsSkippedInSource(object[]? original)
{
return isSource && skipSymbolsInSource is [..] && original is [..]
? original.Except(skipSymbolsInSource).ToArray()
: original;
}
}
}
private static Func<ModuleSymbol, Symbol> ExtensionMember(string containerName, string memberName)
{
return module => module.GlobalNamespace
.GetMember<NamedTypeSymbol>(containerName)
.GetMembers("")
.Cast<NamedTypeSymbol>()
.SelectMany(block => block.GetMembers(memberName))
.SingleOrDefault()
?? throw new InvalidOperationException($"Cannot find '{containerName}.{memberName}'.");
}
private static Func<ModuleSymbol, Symbol> Overload(string qualifiedName, int parameterCount)
{
return module => module.GlobalNamespace
.GetMembersByQualifiedName<MethodSymbol>(qualifiedName)
.SingleOrDefault(m => m.Parameters.Length == parameterCount)
?? throw new InvalidOperationException($"Cannot find '{qualifiedName}' with {parameterCount} parameters.");
}
private static Func<ModuleSymbol, Symbol> OverloadByReturnType(string qualifiedName, string returnType)
{
return module =>
{
var candidates = module.GlobalNamespace
.GetMembersByQualifiedName<MethodSymbol>(qualifiedName);
return candidates.SingleOrDefault(m => m.ReturnType.ToTestDisplayString() == returnType)
?? throw new InvalidOperationException($"Cannot find '{qualifiedName}' with return type '{returnType}'. " +
$"Found {string.Join(", ", candidates.Select(static m => m.ReturnType.ToTestDisplayString()))}.");
};
}
private static void VerifyMemorySafetyRulesAttribute(
ModuleSymbol module,
bool includesAttributeDefinition,
bool includesAttributeUse,
bool? isSynthesized = null)
{
const string Name = "MemorySafetyRulesAttribute";
const string FullName = $"System.Runtime.CompilerServices.{Name}";
var type = (NamedTypeSymbol)module.GlobalNamespace.GetMember(FullName);
var attribute = module.GetAttributes().SingleOrDefault(a => a.AttributeClass?.Name == Name);
if (includesAttributeDefinition)
{
Assert.NotNull(type);
Assert.NotNull(isSynthesized);
if (isSynthesized.Value)
{
var attributeAttributes = type.GetAttributes()
.Select(a => a.AttributeClass.ToTestDisplayString())
.OrderBy(StringComparer.Ordinal);
Assert.Equal(
[
"Microsoft.CodeAnalysis.EmbeddedAttribute",
"System.AttributeUsageAttribute",
"System.Runtime.CompilerServices.CompilerGeneratedAttribute",
],
attributeAttributes);
}
}
else
{
Assert.Null(type);
if (includesAttributeUse)
{
Assert.NotNull(attribute);
type = attribute.AttributeClass;
}
}
if (type is { })
{
Assert.NotNull(isSynthesized);
Assert.Equal(isSynthesized.Value ? Accessibility.Internal : Accessibility.Public, type.DeclaredAccessibility);
}
else
{
Assert.Null(isSynthesized);
}
if (includesAttributeUse)
{
Assert.NotNull(attribute);
Assert.Equal(type, attribute.AttributeClass);
Assert.Equal([2], attribute.ConstructorArguments.Select(a => a.Value));
Assert.Equal([], attribute.NamedArguments);
}
else
{
Assert.Null(attribute);
}
}
/// <remarks>
/// <paramref name="expectedUnsafeSymbols"/> (and <paramref name="expectedSafeSymbols"/>) should be symbol names (<see cref="string"/>)
/// or symbol getters (<c><![CDATA[Func<ModuleSymbol, Symbol>]]></c>) of symbols that are expected to be unsafe (or safe, respectively).
/// </remarks>
private static void VerifyRequiresUnsafeAttribute(
ModuleSymbol module,
ReadOnlySpan<object> expectedUnsafeSymbols,
ReadOnlySpan<object> expectedSafeSymbols,
object[]? expectedNoAttributeInSource = null,
object[]? expectedNoAttribute = null,
object[]? expectedAttribute = null,
CallerUnsafeMode expectedUnsafeMode = CallerUnsafeMode.Explicit)
{
const string Name = "RequiresUnsafeAttribute";
var expectedNoAttributeInSourceSymbols = (expectedNoAttributeInSource ?? []).SelectAsArray(getSymbol);
var expectedNoAttributeSymbols = (expectedNoAttribute ?? []).SelectAsArray(getSymbol);
var expectedAttributeSymbols = (expectedAttribute ?? []).SelectAsArray(getSymbol);
var seenSymbols = new HashSet<Symbol>();
foreach (var symbol in expectedUnsafeSymbols)
{
verifySymbol(symbol, shouldBeUnsafe: true);
}
foreach (var symbol in expectedSafeSymbols)
{
verifySymbol(symbol, shouldBeUnsafe: false);
}
Assert.All(expectedNoAttributeInSourceSymbols, s => Assert.True(seenSymbols.Contains(s)));
Assert.All(expectedNoAttributeSymbols, s => Assert.True(seenSymbols.Contains(s)));
Assert.All(expectedAttributeSymbols, s => Assert.True(seenSymbols.Contains(s)));
void verifySymbol(object symbolGetter, bool shouldBeUnsafe)
{
var symbol = getSymbol(symbolGetter);
var symbolExpectedUnsafeMode = shouldBeUnsafe ? expectedUnsafeMode : CallerUnsafeMode.None;
Assert.True(symbolExpectedUnsafeMode == symbol.CallerUnsafeMode, $"Expected {symbol.GetType().Name} '{symbol.ToTestDisplayString()}' to have {nameof(CallerUnsafeMode)}.{symbolExpectedUnsafeMode} (got {symbol.CallerUnsafeMode}).");
var attribute = symbol.GetAttributes().SingleOrDefault(a => a.AttributeClass?.Name == Name);
var associatedAttribute = (symbol as MethodSymbol)?.AssociatedSymbol?.GetAttributes().SingleOrDefault(a => a.AttributeClass?.Name == Name);
var hasAttribute = attribute is not null || associatedAttribute is not null;
var shouldHaveAttribute = expectedAttributeSymbols.Contains(symbol) ||
(shouldBeUnsafe && expectedUnsafeMode != CallerUnsafeMode.Implicit &&
(module is not SourceModuleSymbol || !expectedNoAttributeInSourceSymbols.Contains(symbol)) &&
!expectedNoAttributeSymbols.Contains(symbol));
Assert.True(shouldHaveAttribute == hasAttribute,
$"{(shouldHaveAttribute ? "Expected" : "Did not expect")} {symbol.GetType().Name} '{symbol.ToTestDisplayString()}' or its associated symbol to have the attribute.");
Assert.True(seenSymbols.Add(symbol), $"Symbol '{symbol.ToTestDisplayString()}' specified multiple times.");
Assert.True(shouldBeUnsafe || !expectedNoAttributeInSourceSymbols.Contains(symbol),
$"Unexpected safe '{symbol.ToTestDisplayString()}' in {nameof(expectedNoAttributeInSource)}.");
}
Symbol getSymbol(object symbolGetter)
{
var symbol = symbolGetter switch
{
string symbolName => module.GlobalNamespace.GetMember(symbolName),
Func<ModuleSymbol, Symbol> func => func(module),
_ => throw ExceptionUtilities.UnexpectedValue(symbolGetter),
};
Assert.False(symbol is null, $"Cannot find symbol '{symbolGetter}' in {module.GetType().Name}.");
return symbol;
}
}
[Fact]
public void RulesAttribute_Synthesized()
{
var source = """
class C;
""";
CompileAndVerify(source,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false))
.VerifyDiagnostics();
var ref1 = CompileAndVerify(source,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true))
.VerifyDiagnostics()
.GetImageReference();
CompileAndVerify("", [ref1],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true))
.VerifyDiagnostics();
var source2 = """
class B;
""";
CompileAndVerify(source2, [ref1],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true))
.VerifyDiagnostics();
CompileAndVerify(source,
options: TestOptions.ReleaseModule,
verify: Verification.Skipped,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false))
.VerifyDiagnostics();
CreateCompilation(source,
options: TestOptions.ReleaseModule.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS0518: Predefined type 'System.Runtime.CompilerServices.MemorySafetyRulesAttribute' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Runtime.CompilerServices.MemorySafetyRulesAttribute").WithLocation(1, 1));
// Script compilation.
source = "System.Console.WriteLine();";
CompileAndVerify(source,
parseOptions: TestOptions.Script,
options: TestOptions.ReleaseModule,
verify: Verification.Skipped,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false))
.VerifyDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Script,
options: TestOptions.ReleaseModule.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS0518: Predefined type 'System.Runtime.CompilerServices.MemorySafetyRulesAttribute' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Runtime.CompilerServices.MemorySafetyRulesAttribute").WithLocation(1, 1));
// No types and members in the compilation, but the attribute is still synthesized if updated rules are enabled.
source = """
[assembly: System.Reflection.AssemblyDescriptionAttribute(null)]
""";
CompileAndVerify(source,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false))
.VerifyDiagnostics();
CompileAndVerify(source,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true))
.VerifyDiagnostics();
CreateCompilation(source,
options: TestOptions.ReleaseModule.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS0518: Predefined type 'System.Runtime.CompilerServices.MemorySafetyRulesAttribute' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Runtime.CompilerServices.MemorySafetyRulesAttribute").WithLocation(1, 1));
}
[Theory, CombinatorialData]
public void RulesAttribute_TypeForwardedTo(
bool updatedRulesA,
bool updatedRulesB,
bool useCompilationReference)
{
var sourceA = """
public class A { }
""";
var comp = CreateCompilation(sourceA,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(updatedRulesA))
.VerifyDiagnostics();
var refA = AsReference(comp, useCompilationReference);
Assert.Equal(updatedRulesA, comp.SourceModule.UseUpdatedMemorySafetyRules);
CompileAndVerify(comp,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: updatedRulesA, includesAttributeUse: updatedRulesA, isSynthesized: updatedRulesA ? true : null))
.VerifyDiagnostics();
var sourceB = """
using System.Runtime.CompilerServices;
[assembly: TypeForwardedTo(typeof(A))]
""";
comp = CreateCompilation(sourceB, [refA], options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(updatedRulesB));
Assert.Equal(updatedRulesB, comp.SourceModule.UseUpdatedMemorySafetyRules);
CompileAndVerify(comp,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: updatedRulesB, includesAttributeUse: updatedRulesB, isSynthesized: updatedRulesB ? true : null))
.VerifyDiagnostics();
}
[Fact]
public void RulesAttribute_Reflection()
{
var sourceA = """
using System;
using System.Linq;
public class A
{
public static int GetAttributeValue(Type type)
{
var module = type.Assembly.Modules.Single();
var attribute = module.GetCustomAttributes(inherit: false).Single(a => a.GetType().Name == "MemorySafetyRulesAttribute");
var prop = attribute.GetType().GetProperty("Version");
return (int)prop.GetValue(attribute);
}
}
""";
var refA = CreateCompilation(sourceA,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.EmitToImageReference();
var sourceB = """
using System;
class B : A
{
static void Main()
{
Console.Write(GetAttributeValue(typeof(A)));
Console.Write(" ");
Console.Write(GetAttributeValue(typeof(B)));
}
}
""";
CompileAndVerify(sourceB, [refA],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules(),
expectedOutput: "2 2")
.VerifyDiagnostics();
}
[Fact]
public void RulesAttribute_FromSource()
{
var source = """
class C;
""";
CompileAndVerify([source, MemorySafetyRulesAttributeDefinition],
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, isSynthesized: false))
.VerifyDiagnostics();
CompileAndVerify([source, MemorySafetyRulesAttributeDefinition],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: false))
.VerifyDiagnostics();
}
[Theory, CombinatorialData]
public void RulesAttribute_FromMetadata(bool useCompilationReference)
{
var comp = CreateCompilation(MemorySafetyRulesAttributeDefinition);
CompileAndVerify(comp,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, isSynthesized: false))
.VerifyDiagnostics();
var ref1 = AsReference(comp, useCompilationReference);
var source = """
class C;
""";
CompileAndVerify(source, [ref1],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: true, isSynthesized: false))
.VerifyDiagnostics();
}
[Theory, CombinatorialData]
public void RulesAttribute_FromMetadata_Multiple(bool useCompilationReference)
{
var comp1 = CreateCompilation(MemorySafetyRulesAttributeDefinition).VerifyDiagnostics();
var ref1 = AsReference(comp1, useCompilationReference);
var comp2 = CreateCompilation(MemorySafetyRulesAttributeDefinition).VerifyDiagnostics();
var ref2 = AsReference(comp2, useCompilationReference);
var source = """
class C;
""";
// Ambiguous attribute definitions from references => synthesize our own.
CompileAndVerify(source, [ref1, ref2],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true))
.VerifyDiagnostics();
// Also defined in source.
CompileAndVerify([source, MemorySafetyRulesAttributeDefinition], [ref1, ref2],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: false))
.VerifyDiagnostics();
}
[Theory, CombinatorialData]
public void RulesAttribute_FromMetadata_Multiple_AndCorLib(bool useCompilationReference)
{
var corlibSource = """
namespace System
{
public class Object;
public class ValueType;
public class Attribute;
public struct Void;
public struct Int32;
public struct Boolean;
public class AttributeUsageAttribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public class Enum;
public enum AttributeTargets;
}
""";
var corlib = CreateEmptyCompilation([corlibSource, MemorySafetyRulesAttributeDefinition]).VerifyDiagnostics();
var corlibRef = AsReference(corlib, useCompilationReference);
var comp1 = CreateEmptyCompilation(MemorySafetyRulesAttributeDefinition, [corlibRef]).VerifyDiagnostics();
var ref1 = AsReference(comp1, useCompilationReference);
var comp2 = CreateEmptyCompilation(MemorySafetyRulesAttributeDefinition, [corlibRef]).VerifyDiagnostics();
var ref2 = AsReference(comp2, useCompilationReference);
var source = """
class C;
""";
// Using the attribute from corlib even if there are ambiguous definitions in other references.
var verifier = CompileAndVerify(CreateEmptyCompilation(source, [ref1, ref2, corlibRef],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules()),
verify: Verification.Skipped,
symbolValidator: m => VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: true, isSynthesized: false));
verifier.Diagnostics.WhereAsArray(d => d.Code != (int)ErrorCode.WRN_NoRuntimeMetadataVersion).Verify();
var comp = (CSharpCompilation)verifier.Compilation;
Assert.Same(comp.Assembly.CorLibrary, comp.GetReferencedAssemblySymbol(corlibRef));
}
[Theory]
[InlineData(0)]
[InlineData(-1)]
[InlineData(1)]
[InlineData(2, true)]
[InlineData(3)]
[InlineData(int.MinValue)]
[InlineData(int.MaxValue)]
public void RulesAttribute_FromMetadata_Version(int version, bool correctVersion = false)
{
// [module: MemorySafetyRules({version})]
// public class A { public static void M() => throw null; }
var sourceA = $$"""
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{version}}) }
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class public A
{
.method public static void M() { ldnull throw }
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB = """
class B
{
void M() => A.M();
}
""";
var comp = CreateCompilation(sourceB, [refA]);
if (correctVersion)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyDiagnostics(
// (3,17): error CS9103: 'A.M()' is defined in a module with an unrecognized System.Runtime.CompilerServices.MemorySafetyRulesAttribute version, expecting '2'.
// void M() => A.M();
Diagnostic(ErrorCode.ERR_UnrecognizedAttributeVersion, "A.M").WithArguments("A.M()", "System.Runtime.CompilerServices.MemorySafetyRulesAttribute", "2").WithLocation(3, 17));
}
var method = comp.GetMember<MethodSymbol>("B.M");
Assert.False(method.ContainingModule.UseUpdatedMemorySafetyRules);
// 'A.M' not used => no error.
CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics();
}
[Theory]
[InlineData(2, 0, true)]
[InlineData(0, 2, false)]
public void RulesAttribute_FromMetadata_Version_Multiple(int version1, int version2, bool correctVersion)
{
// [module: MemorySafetyRules({version1})]
// [module: MemorySafetyRules({version2})]
// public class A { public static void M() => throw null; }
var sourceA = $$"""
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{version1}}) }
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{version2}}) }
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class public A
{
.method public static void M() { ldnull throw }
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var a = CreateCompilation("", [refA]).GetReferencedAssemblySymbol(refA);
Assert.Equal(correctVersion, a.Modules.Single().UseUpdatedMemorySafetyRules);
var sourceB = """
class B
{
void M() => A.M();
}
""";
var comp = CreateCompilation(sourceB, [refA]);
if (correctVersion)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyDiagnostics(
// (3,17): error CS9103: 'A.M()' is defined in a module with an unrecognized System.Runtime.CompilerServices.MemorySafetyRulesAttribute version, expecting '2'.
// void M() => A.M();
Diagnostic(ErrorCode.ERR_UnrecognizedAttributeVersion, "A.M").WithArguments("A.M()", "System.Runtime.CompilerServices.MemorySafetyRulesAttribute", "2").WithLocation(3, 17));
}
var method = comp.GetMember<MethodSymbol>("B.M");
Assert.False(method.ContainingModule.UseUpdatedMemorySafetyRules);
// 'A.M' not used => no error.
CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics();
}
[Fact]
public void RulesAttribute_FromMetadata_UnrecognizedConstructor_NoArguments()
{
// [module: MemorySafetyRules()]
// public class A { public static void M() => throw null; }
var sourceA = """
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor() = ( 01 00 00 00 )
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public A
{
.method public static void M() { ldnull throw }
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB = """
class B
{
void M() => A.M();
}
""";
var comp = CreateCompilation(sourceB, [refA]);
comp.VerifyDiagnostics(
// (3,17): error CS9103: 'A.M()' is defined in a module with an unrecognized System.Runtime.CompilerServices.MemorySafetyRulesAttribute version, expecting '2'.
// void M() => A.M();
Diagnostic(ErrorCode.ERR_UnrecognizedAttributeVersion, "A.M").WithArguments("A.M()", "System.Runtime.CompilerServices.MemorySafetyRulesAttribute", "2").WithLocation(3, 17));
var method = comp.GetMember<MethodSymbol>("B.M");
Assert.False(method.ContainingModule.UseUpdatedMemorySafetyRules);
// 'A.M' not used => no error.
CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics();
}
[Fact]
public void RulesAttribute_FromMetadata_UnrecognizedConstructor_StringArgument()
{
// [module: MemorySafetyRules("2")]
// public class A { public static void M() => throw null; }
var sourceA = """
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(string) = {string('2')}
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(string version) cil managed { ret }
}
.class public A
{
.method public static void M() { ldnull throw }
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB = """
class B
{
void M() => A.M();
}
""";
var comp = CreateCompilation(sourceB, [refA]);
comp.VerifyDiagnostics(
// (3,17): error CS9103: 'A.M()' is defined in a module with an unrecognized System.Runtime.CompilerServices.MemorySafetyRulesAttribute version, expecting '2'.
// void M() => A.M();
Diagnostic(ErrorCode.ERR_UnrecognizedAttributeVersion, "A.M").WithArguments("A.M()", "System.Runtime.CompilerServices.MemorySafetyRulesAttribute", "2").WithLocation(3, 17));
var method = comp.GetMember<MethodSymbol>("B.M");
Assert.False(method.ContainingModule.UseUpdatedMemorySafetyRules);
// 'A.M' not used => no error.
CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics();
}
[Fact]
public void RulesAttribute_MissingConstructor()
{
var source1 = """
namespace System.Runtime.CompilerServices
{
public sealed class MemorySafetyRulesAttribute : Attribute { }
}
""";
var source2 = """
class C;
""";
CreateCompilation([source1, source2]).VerifyEmitDiagnostics();
CreateCompilation([source1, source2],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.VerifyEmitDiagnostics(
// error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.MemorySafetyRulesAttribute..ctor'
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Runtime.CompilerServices.MemorySafetyRulesAttribute", ".ctor").WithLocation(1, 1));
CreateCompilation([source1, source2],
options: TestOptions.ReleaseModule.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.MemorySafetyRulesAttribute..ctor'
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Runtime.CompilerServices.MemorySafetyRulesAttribute", ".ctor").WithLocation(1, 1));
}
[Theory, CombinatorialData]
public void RulesAttribute_ReferencedInSource(
bool updatedRules,
bool useCompilationReference)
{
var comp = CreateCompilation(MemorySafetyRulesAttributeDefinition).VerifyDiagnostics();
var ref1 = AsReference(comp, useCompilationReference);
var source = """
using System.Runtime.CompilerServices;
[assembly: MemorySafetyRules(2)]
[module: MemorySafetyRules(2)]
""";
comp = CreateCompilation(source, [ref1], options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(updatedRules));
comp.VerifyDiagnostics(
// (3,10): error CS8335: Do not use 'System.Runtime.CompilerServices.MemorySafetyRulesAttribute'. This is reserved for compiler usage.
// [module: MemorySafetyRules(2)]
Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, "MemorySafetyRules(2)").WithArguments("System.Runtime.CompilerServices.MemorySafetyRulesAttribute").WithLocation(3, 10));
}
[Theory, CombinatorialData]
public void Pointer_Variable_SafeContext(bool allowUnsafe)
{
var source = """
int* x = null;
""";
var expectedDiagnostics = new[]
{
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe)).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe)).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe).WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe).WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe).WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_Variable_SafeContext_Var()
{
var source = """
var x = GetPointer();
int* GetPointer() => null;
""";
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// var x = GetPointer();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "GetPointer()").WithArguments("updated memory safety rules").WithLocation(1, 9),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* GetPointer() => null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(2, 1));
}
[Fact]
public void Pointer_Variable_SafeContext_InIterator()
{
var source = """
unsafe
{
M();
System.Collections.Generic.IEnumerable<int> M()
{
int* p = null;
yield return 1;
}
}
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(
// (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9));
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (6,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(6, 9));
var expectedDiagnostics = new[]
{
// (6,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// int* p = null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "int*").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 9),
};
CreateCompilation(source,
parseOptions: TestOptions.Regular12,
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular12,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
}
[Fact]
public void Pointer_Variable_UnsafeContext()
{
var source = """
unsafe { int* x = null; }
""";
var expectedDiagnostics = new[]
{
// (1,1): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { int* x = null; }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(1, 1),
};
CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyEmitDiagnostics();
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
}
[Fact]
public void Pointer_Variable_UsingAlias_SafeContext()
{
var source = """
using X = int*;
X x = null;
""";
var expectedDiagnostics = new[]
{
// (1,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// using X = int*;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 11),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// X x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "X").WithLocation(2, 1),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,11): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// using X = int*;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 11),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// X x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "X").WithArguments("updated memory safety rules").WithLocation(2, 1));
}
[Fact]
public void Pointer_Variable_UsingAlias_UnsafeContext()
{
var source = """
using unsafe X = int*;
unsafe { X x = null; }
""";
var expectedDiagnostics = new[]
{
// (1,7): error CS0227: Unsafe code may only appear if compiling with /unsafe
// using unsafe X = int*;
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(1, 7),
// (2,1): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { X x = null; }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(2, 1),
};
CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyEmitDiagnostics();
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
}
[Theory, CombinatorialData]
public void Pointer_Dereference_SafeContext(bool allowUnsafe)
{
var source = """
int* x = null;
int y = *x;
""";
CreateCompilation(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe))
.VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int y = *x;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 10));
var expectedDiagnostics = new[]
{
// (2,9): error CS9360: This operation may only be used in an unsafe context
// int y = *x;
Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(2, 9),
};
CreateCompilation(source,
options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe).WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe).WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithAllowUnsafe(allowUnsafe).WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = *x;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 10),
// (2,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = *x;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "*").WithArguments("updated memory safety rules").WithLocation(2, 9));
}
[Fact]
public void Pointer_Dereference_SafeContext_InIterator()
{
var source = """
unsafe
{
M();
System.Collections.Generic.IEnumerable<int> M()
{
int* p = null;
int y = *p;
yield return 1;
}
}
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(
// (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 9),
// (7,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int y = *p;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(7, 18));
var expectedDiagnostics = new[]
{
// (7,17): error CS9360: This operation may only be used in an unsafe context
// int y = *p;
Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(7, 17),
};
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (6,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(6, 9),
// (7,18): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = *p;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("updated memory safety rules").WithLocation(7, 18),
// (7,17): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = *p;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "*").WithArguments("updated memory safety rules").WithLocation(7, 17));
expectedDiagnostics =
[
// (6,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// int* p = null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "int*").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 9),
// (7,18): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// int y = *p;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "p").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 18),
];
CreateCompilation(source,
parseOptions: TestOptions.Regular12,
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular12,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
}
[Fact]
public void Pointer_Dereference_SafeContext_Null()
{
var source = """
int x = *null;
""";
var expectedDiagnostics = new[]
{
// (1,9): error CS0193: The * or -> operator must be applied to a pointer
// int x = *null;
Diagnostic(ErrorCode.ERR_PtrExpected, "*null").WithLocation(1, 9),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
}
[Fact]
public void Pointer_Dereference_UnsafeContext()
{
var source = """
int* x = null;
unsafe { int y = *x; }
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_MemberAccess_SafeContext()
{
var source = """
int* x = null;
string s = x->ToString();
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// string s = x->ToString();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 12));
var expectedDiagnostics = new[]
{
// (2,13): error CS9360: This operation may only be used in an unsafe context
// string s = x->ToString();
Diagnostic(ErrorCode.ERR_UnsafeOperation, "->").WithLocation(2, 13),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,12): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// string s = x->ToString();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 12),
// (2,13): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// string s = x->ToString();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "->").WithArguments("updated memory safety rules").WithLocation(2, 13));
}
[Fact]
public void Pointer_MemberAccess_SafeContext_Null()
{
var source = """
string s = null->ToString();
""";
var expectedDiagnostics = new[]
{
// (1,12): error CS0193: The * or -> operator must be applied to a pointer
// string s = null->ToString();
Diagnostic(ErrorCode.ERR_PtrExpected, "null->ToString").WithLocation(1, 12),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
}
[Fact]
public void Pointer_MemberAccess_UnsafeContext()
{
var source = """
int* x = null;
unsafe { string s = x->ToString(); }
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_MemberAccessViaDereference_SafeContext()
{
var source = """
int* x = null;
string s = (*x).ToString();
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// string s = (*x).ToString();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 14));
var expectedDiagnostics = new[]
{
// (2,13): error CS9360: This operation may only be used in an unsafe context
// string s = (*x).ToString();
Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(2, 13),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,14): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// string s = (*x).ToString();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 14),
// (2,13): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// string s = (*x).ToString();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "*").WithArguments("updated memory safety rules").WithLocation(2, 13));
}
[Fact]
public void Pointer_MemberAccessViaDereference_UnsafeContext()
{
var source = """
int* x = null;
unsafe { string s = (*x).ToString(); }
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_ElementAccess_SafeContext()
{
var source = """
int* x = null;
x[0] = 1;
int y = x[1];
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// x[0] = 1;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 1),
// (3,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int y = x[1];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(3, 9));
var expectedDiagnostics = new[]
{
// (2,2): error CS9360: This operation may only be used in an unsafe context
// x[0] = 1;
Diagnostic(ErrorCode.ERR_UnsafeOperation, "[").WithLocation(2, 2),
// (3,10): error CS9360: This operation may only be used in an unsafe context
// int y = x[1];
Diagnostic(ErrorCode.ERR_UnsafeOperation, "[").WithLocation(3, 10),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0] = 1;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,2): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0] = 1;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "[").WithArguments("updated memory safety rules").WithLocation(2, 2),
// (3,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = x[1];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(3, 9),
// (3,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = x[1];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "[").WithArguments("updated memory safety rules").WithLocation(3, 10));
}
[Fact]
public void Pointer_ElementAccess_SafeContext_MultipleIndices()
{
var source = """
int* x = null;
x[0, 1] = 1;
int y = x[2, 3];
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// x[0, 1] = 1;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 1),
// (2,1): error CS0196: A pointer must be indexed by only one value
// x[0, 1] = 1;
Diagnostic(ErrorCode.ERR_PtrIndexSingle, "x[0, 1]").WithLocation(2, 1),
// (3,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int y = x[2, 3];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(3, 9),
// (3,9): error CS0196: A pointer must be indexed by only one value
// int y = x[2, 3];
Diagnostic(ErrorCode.ERR_PtrIndexSingle, "x[2, 3]").WithLocation(3, 9));
var expectedDiagnostics = new[]
{
// (2,1): error CS0196: A pointer must be indexed by only one value
// x[0, 1] = 1;
Diagnostic(ErrorCode.ERR_PtrIndexSingle, "x[0, 1]").WithLocation(2, 1),
// (3,9): error CS0196: A pointer must be indexed by only one value
// int y = x[2, 3];
Diagnostic(ErrorCode.ERR_PtrIndexSingle, "x[2, 3]").WithLocation(3, 9),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0, 1] = 1;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,1): error CS0196: A pointer must be indexed by only one value
// x[0, 1] = 1;
Diagnostic(ErrorCode.ERR_PtrIndexSingle, "x[0, 1]").WithLocation(2, 1),
// (3,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int y = x[2, 3];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(3, 9),
// (3,9): error CS0196: A pointer must be indexed by only one value
// int y = x[2, 3];
Diagnostic(ErrorCode.ERR_PtrIndexSingle, "x[2, 3]").WithLocation(3, 9));
}
[Fact]
public void Pointer_ElementAccess_SafeContext_ArrayOfPointers()
{
var source = """
int*[] x = [];
x[0] = null;
_ = x[1];
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int*[] x = [];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// x[0] = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// x[0] = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[0]").WithLocation(2, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// x[0] = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[0] = null").WithLocation(2, 1),
// (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = x[1];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(3, 5),
// (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = x[1];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[1]").WithLocation(3, 5),
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = x[1];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "_ = x[1]").WithLocation(3, 1));
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int*[] x = [];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0] = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0] = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x[0]").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0] = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x[0] = null").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (3,5): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// _ = x[1];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(3, 5),
// (3,5): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// _ = x[1];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x[1]").WithArguments("updated memory safety rules").WithLocation(3, 5),
// (3,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// _ = x[1];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "_ = x[1]").WithArguments("updated memory safety rules").WithLocation(3, 1));
}
[Fact]
public void Pointer_ElementAccess_SafeContext_FunctionPointer()
{
var source = """
delegate*<void> x = null;
x[0] = null;
_ = x[1];
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// delegate*<void> x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(1, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// x[0] = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(2, 1),
// (2,1): error CS0021: Cannot apply indexing with [] to an expression of type 'delegate*<void>'
// x[0] = null;
Diagnostic(ErrorCode.ERR_BadIndexLHS, "x[0]").WithArguments("delegate*<void>").WithLocation(2, 1),
// (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = x[1];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x").WithLocation(3, 5),
// (3,5): error CS0021: Cannot apply indexing with [] to an expression of type 'delegate*<void>'
// _ = x[1];
Diagnostic(ErrorCode.ERR_BadIndexLHS, "x[1]").WithArguments("delegate*<void>").WithLocation(3, 5));
var expectedDiagnostics = new[]
{
// (2,1): error CS0021: Cannot apply indexing with [] to an expression of type 'delegate*<void>'
// x[0] = null;
Diagnostic(ErrorCode.ERR_BadIndexLHS, "x[0]").WithArguments("delegate*<void>").WithLocation(2, 1),
// (3,5): error CS0021: Cannot apply indexing with [] to an expression of type 'delegate*<void>'
// _ = x[1];
Diagnostic(ErrorCode.ERR_BadIndexLHS, "x[1]").WithArguments("delegate*<void>").WithLocation(3, 5),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// delegate*<void> x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// x[0] = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,1): error CS0021: Cannot apply indexing with [] to an expression of type 'delegate*<void>'
// x[0] = null;
Diagnostic(ErrorCode.ERR_BadIndexLHS, "x[0]").WithArguments("delegate*<void>").WithLocation(2, 1),
// (3,5): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// _ = x[1];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("updated memory safety rules").WithLocation(3, 5),
// (3,5): error CS0021: Cannot apply indexing with [] to an expression of type 'delegate*<void>'
// _ = x[1];
Diagnostic(ErrorCode.ERR_BadIndexLHS, "x[1]").WithArguments("delegate*<void>").WithLocation(3, 5));
}
[Fact]
public void Pointer_ElementAccess_UnsafeContext()
{
var source = """
int* x = null;
unsafe
{
x[0] = 1;
int y = x[1];
}
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_Function_Variable_SafeContext()
{
var source = """
delegate*<void> f = null;
""";
var expectedDiagnostics = new[]
{
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// delegate*<void> f = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(1, 1),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// delegate*<void> f = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_Function_Variable_UnsafeContext()
{
var source = """
unsafe { delegate*<void> f = null; }
""";
var expectedDiagnostics = new[]
{
// (1,1): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { delegate*<void> f = null; }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(1, 1),
};
CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyEmitDiagnostics();
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
}
[Fact]
public void Pointer_Function_Variable_UsingAlias_SafeContext()
{
var source = """
using X = delegate*<void>;
X x = null;
""";
var expectedDiagnostics = new[]
{
// (1,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// using X = delegate*<void>;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(1, 11),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// X x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "X").WithLocation(2, 1),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
// https://github.com/dotnet/roslyn/issues/77389
expectedDiagnostics = PlatformInformation.IsWindows
? [
// error CS8911: Using a function pointer type in this context is not supported.
Diagnostic(ErrorCode.ERR_FunctionPointerTypesInAttributeNotSupported).WithLocation(1, 1),
]
: [];
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,11): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// using X = delegate*<void>;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("updated memory safety rules").WithLocation(1, 11),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// X x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "X").WithArguments("updated memory safety rules").WithLocation(2, 1));
}
[Fact]
public void Pointer_Function_Variable_UsingAlias_UnsafeContext()
{
var source = """
using unsafe X = delegate*<void>;
unsafe { X x = null; }
""";
var expectedDiagnostics = new[]
{
// (1,7): error CS0227: Unsafe code may only appear if compiling with /unsafe
// using unsafe X = delegate*<void>;
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(1, 7),
// (2,1): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { X x = null; }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(2, 1),
};
CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
// https://github.com/dotnet/roslyn/issues/77389
expectedDiagnostics = PlatformInformation.IsWindows
? [
// error CS8911: Using a function pointer type in this context is not supported.
Diagnostic(ErrorCode.ERR_FunctionPointerTypesInAttributeNotSupported).WithLocation(1, 1),
]
: [];
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics()
.VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void Pointer_Function_Call_SafeContext()
{
var source = """
delegate*<string> x = null;
string s = x();
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// delegate*<string> x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(1, 1),
// (2,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// string s = x();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x()").WithLocation(2, 12));
var expectedDiagnostics = new[]
{
// (2,12): error CS9360: This operation may only be used in an unsafe context
// string s = x();
Diagnostic(ErrorCode.ERR_UnsafeOperation, "x()").WithLocation(2, 12),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// delegate*<string> x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,12): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// string s = x();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x()").WithArguments("updated memory safety rules").WithLocation(2, 12));
}
[Fact]
public void Pointer_Function_Call_UnsafeContext()
{
var source = """
delegate*<string> x = null;
unsafe { string s = x(); }
""";
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// delegate*<string> x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Pointer_Function_Call_UsingAlias()
{
var source = """
using X = delegate*<string>;
X x = null;
string s = x();
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (1,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// using X = delegate*<string>;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(1, 11),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// X x = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "X").WithLocation(2, 1),
// (3,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// string s = x();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x()").WithLocation(3, 12));
var expectedDiagnostics = new[]
{
// (3,12): error CS9360: This operation may only be used in an unsafe context
// string s = x();
Diagnostic(ErrorCode.ERR_UnsafeOperation, "x()").WithLocation(3, 12),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,11): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// using X = delegate*<string>;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("updated memory safety rules").WithLocation(1, 11),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// X x = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "X").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (3,12): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// string s = x();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x()").WithArguments("updated memory safety rules").WithLocation(3, 12));
}
[Fact]
public void Pointer_AddressOf_SafeContext()
{
var source = """
int x;
int* p = &x;
""";
var expectedDiagnostics = new[]
{
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = &x;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 1),
// (2,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = &x;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(2, 10),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = &x;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = &x;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("updated memory safety rules").WithLocation(2, 10));
}
[Fact]
public void Pointer_AddressOf_SafeContext_Const()
{
var source = """
const int x = 1;
int* p = &x;
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = &x;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 1),
// (2,11): error CS0211: Cannot take the address of the given expression
// int* p = &x;
Diagnostic(ErrorCode.ERR_InvalidAddrOp, "x").WithLocation(2, 11));
var expectedDiagnostics = new[]
{
// (2,11): error CS0211: Cannot take the address of the given expression
// int* p = &x;
Diagnostic(ErrorCode.ERR_InvalidAddrOp, "x").WithLocation(2, 11),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = &x;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,11): error CS0211: Cannot take the address of the given expression
// int* p = &x;
Diagnostic(ErrorCode.ERR_InvalidAddrOp, "x").WithLocation(2, 11));
}
[Fact]
public void Pointer_AddressOf_UnsafeContext()
{
var source = """
int x;
unsafe { int* p = &x; }
""";
var expectedDiagnostics = new[]
{
// (2,1): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { int* p = &x; }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(2, 1),
};
CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyEmitDiagnostics();
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
}
[Fact]
public void Pointer_Fixed_SafeContext()
{
var source = """
class C
{
static int x;
static void Main()
{
fixed (int* p = &x) { }
}
}
""";
var expectedDiagnostics = new[]
{
// (6,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "fixed (int* p = &x) { }").WithLocation(6, 9),
// (6,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 16),
// (6,25): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(6, 25),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (6,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "fixed (int* p = &x) { }").WithArguments("updated memory safety rules").WithLocation(6, 9),
// (6,16): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(6, 16),
// (6,25): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("updated memory safety rules").WithLocation(6, 25));
}
[Fact]
public void Pointer_Fixed_PatternBased()
{
var source = """
class C
{
static void Main()
{
fixed (int* p = new S()) { }
}
}
struct S
{
public ref readonly int GetPinnableReference() => throw null;
}
""";
var expectedDiagnostics = new[]
{
// (5,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = new S()) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "fixed (int* p = new S()) { }").WithLocation(5, 9),
// (5,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = new S()) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(5, 16),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (5,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = new S()) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "fixed (int* p = new S()) { }").WithArguments("updated memory safety rules").WithLocation(5, 9),
// (5,16): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = new S()) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(5, 16));
}
[Fact]
public void Pointer_Fixed_SafeContext_AlreadyFixed()
{
var source = """
int x;
fixed (int* p = &x) { }
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "fixed (int* p = &x) { }").WithLocation(2, 1),
// (2,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 8),
// (2,17): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FixedNotNeeded, "&x").WithLocation(2, 17));
var expectedDiagnostics = new[]
{
// (2,17): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FixedNotNeeded, "&x").WithLocation(2, 17),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "fixed (int* p = &x) { }").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,8): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(2, 8),
// (2,17): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression
// fixed (int* p = &x) { }
Diagnostic(ErrorCode.ERR_FixedNotNeeded, "&x").WithLocation(2, 17));
}
[Fact]
public void Pointer_Fixed_UnsafeContext()
{
var source = """
class C
{
static int x;
static void Main()
{
unsafe { fixed (int* p = &x) { } }
}
}
""";
var expectedDiagnostics = new[]
{
// (6,9): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { fixed (int* p = &x) { } }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(6, 9),
};
CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe).VerifyEmitDiagnostics();
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
}
[Fact]
public void Pointer_Arithmetic_SafeContext()
{
var source = """
int* p = null;
p++;
int* p2 = p + 2;
long x = p - p;
bool b = p > p2;
""";
var expectedDiagnostics = new[]
{
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// p++;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(2, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// p++;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p++").WithLocation(2, 1),
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p2 = p + 2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 1),
// (3,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p2 = p + 2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(3, 11),
// (3,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p2 = p + 2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p + 2").WithLocation(3, 11),
// (4,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// long x = p - p;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(4, 10),
// (4,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// long x = p - p;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(4, 14),
// (5,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// bool b = p > p2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(5, 10),
// (5,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// bool b = p > p2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p2").WithLocation(5, 14),
};
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = null;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// p++;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// p++;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p++").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (3,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p2 = p + 2;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(3, 1),
// (3,11): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p2 = p + 2;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("updated memory safety rules").WithLocation(3, 11),
// (3,11): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p2 = p + 2;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p + 2").WithArguments("updated memory safety rules").WithLocation(3, 11),
// (4,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// long x = p - p;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("updated memory safety rules").WithLocation(4, 10),
// (4,14): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// long x = p - p;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("updated memory safety rules").WithLocation(4, 14),
// (5,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// bool b = p > p2;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("updated memory safety rules").WithLocation(5, 10),
// (5,14): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// bool b = p > p2;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "p2").WithArguments("updated memory safety rules").WithLocation(5, 14));
}
[Fact]
public void SizeOf_SafeContext()
{
var source = """
_ = sizeof(int);
_ = sizeof(nint);
_ = sizeof(S);
struct S;
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (2,5): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context
// _ = sizeof(nint);
Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(2, 5),
// (3,5): error CS0233: 'S' does not have a predefined size, therefore sizeof can only be used in an unsafe context
// _ = sizeof(S);
Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(S)").WithArguments("S").WithLocation(3, 5));
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()).VerifyEmitDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,5): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// _ = sizeof(nint);
Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("updated memory safety rules").WithLocation(2, 5),
// (3,5): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// _ = sizeof(S);
Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(S)").WithArguments("updated memory safety rules").WithLocation(3, 5));
}
[Fact]
public void FixedSizeBuffer_SafeContext()
{
var source = """
var s = new S();
int* p = s.y;
int z = s.x[100];
struct S
{
public fixed int x[5], y[10];
}
""";
CreateCompilation(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = s.y;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 1),
// (2,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* p = s.y;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "s.y").WithLocation(2, 10),
// (3,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int z = s.x[100];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "s.x").WithLocation(3, 9),
// (7,22): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public fixed int x[5], y[10];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[5]").WithLocation(7, 22));
var expectedDiagnostics = new[]
{
// (3,12): error CS9360: This operation may only be used in an unsafe context
// int z = s.x[100];
Diagnostic(ErrorCode.ERR_UnsafeOperation, "[").WithLocation(3, 12),
};
CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = s.y;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(2, 1),
// (2,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* p = s.y;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.y").WithArguments("updated memory safety rules").WithLocation(2, 10),
// (3,9): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int z = s.x[100];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "s.x").WithArguments("updated memory safety rules").WithLocation(3, 9),
// (3,12): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int z = s.x[100];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "[").WithArguments("updated memory safety rules").WithLocation(3, 12),
// (7,22): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public fixed int x[5], y[10];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "x[5]").WithArguments("updated memory safety rules").WithLocation(7, 22));
}
[Fact]
public void SkipLocalsInit_NeedsUnsafe()
{
var source = """
class C { [System.Runtime.CompilerServices.SkipLocalsInit] void M() { } }
namespace System.Runtime.CompilerServices
{
public class SkipLocalsInitAttribute : Attribute;
}
""";
var expectedDiagnostics = new[]
{
// (1,12): error CS0227: Unsafe code may only appear if compiling with /unsafe
// class C { [System.Runtime.CompilerServices.SkipLocalsInit] void M() { } }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "System.Runtime.CompilerServices.SkipLocalsInit").WithLocation(1, 12),
};
CreateCompilation(source, options: TestOptions.ReleaseDll)
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, options: TestOptions.UnsafeReleaseDll)
.VerifyEmitDiagnostics();
CreateCompilation(source, options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyEmitDiagnostics();
}
[Fact]
public void StackAlloc_SafeContext()
{
var source = """
int* x = stackalloc int[3];
System.Span<int> y = stackalloc int[5];
M();
[System.Runtime.CompilerServices.SkipLocalsInit]
void M()
{
System.Span<int> a = stackalloc int[5];
System.Span<int> b = stackalloc int[] { 1 };
System.Span<int> d = stackalloc int[2] { 1, 2 };
System.Span<int> e = stackalloc int[3] { 1, 2 };
}
namespace System.Runtime.CompilerServices
{
public class SkipLocalsInitAttribute : Attribute;
}
""";
CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = stackalloc int[3];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 1),
// (1,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* x = stackalloc int[3];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc int[3]").WithLocation(1, 10),
// (11,26): error CS0847: An array initializer of length '3' is expected
// System.Span<int> e = stackalloc int[3] { 1, 2 };
Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc int[3] { 1, 2 }").WithArguments("3").WithLocation(11, 26));
var expectedDiagnostics = new[]
{
// (8,26): error CS9361: stackalloc expression without an initializer inside SkipLocalsInit may only be used in an unsafe context
// System.Span<int> a = stackalloc int[5];
Diagnostic(ErrorCode.ERR_UnsafeUninitializedStackAlloc, "stackalloc int[5]").WithLocation(8, 26),
// (11,26): error CS0847: An array initializer of length '3' is expected
// System.Span<int> e = stackalloc int[3] { 1, 2 };
Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc int[3] { 1, 2 }").WithArguments("3").WithLocation(11, 26),
};
CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilationWithSpan(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilationWithSpan(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = stackalloc int[3];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("updated memory safety rules").WithLocation(1, 1),
// (1,10): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// int* x = stackalloc int[3];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "stackalloc int[3]").WithArguments("updated memory safety rules").WithLocation(1, 10),
// (8,26): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// System.Span<int> a = stackalloc int[5];
Diagnostic(ErrorCode.ERR_FeatureInPreview, "stackalloc int[5]").WithArguments("updated memory safety rules").WithLocation(8, 26),
// (11,26): error CS0847: An array initializer of length '3' is expected
// System.Span<int> e = stackalloc int[3] { 1, 2 };
Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc int[3] { 1, 2 }").WithArguments("3").WithLocation(11, 26));
}
[Fact]
public void StackAlloc_UnsafeContext()
{
var source = """
unsafe { System.Span<int> y = stackalloc int[5]; }
M();
[System.Runtime.CompilerServices.SkipLocalsInit]
void M()
{
unsafe { System.Span<int> a = stackalloc int[5]; }
unsafe { System.Span<int> e = stackalloc int[3] { 1, 2 }; }
}
namespace System.Runtime.CompilerServices
{
public class SkipLocalsInitAttribute : Attribute;
}
""";
var expectedDiagnostics = new[]
{
// (8,35): error CS0847: An array initializer of length '3' is expected
// unsafe { System.Span<int> e = stackalloc int[3] { 1, 2 }; }
Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "stackalloc int[3] { 1, 2 }").WithArguments("3").WithLocation(8, 35),
};
CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilationWithSpan(source,
parseOptions: TestOptions.RegularNext,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilationWithSpan(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(expectedDiagnostics);
}
[Fact]
public void StackAlloc_Lambda()
{
var source = """
var lam = [System.Runtime.CompilerServices.SkipLocalsInit] () =>
{
System.Span<int> a = stackalloc int[5];
int* b = stackalloc int[3];
unsafe { System.Span<int> c = stackalloc int[1]; }
};
namespace System.Runtime.CompilerServices
{
public class SkipLocalsInitAttribute : Attribute;
}
""";
CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,26): error CS9361: stackalloc expression without an initializer inside SkipLocalsInit may only be used in an unsafe context
// System.Span<int> a = stackalloc int[5];
Diagnostic(ErrorCode.ERR_UnsafeUninitializedStackAlloc, "stackalloc int[5]").WithLocation(3, 26));
}
[Fact]
public void Member_LangVersion()
{
CSharpTestSource source =
[
"""
#pragma warning disable CS8321 // unused local function
[System.Runtime.CompilerServices.RequiresUnsafe] void F() { }
class C
{
[System.Runtime.CompilerServices.RequiresUnsafe] void M() { }
[System.Runtime.CompilerServices.RequiresUnsafe] int P { get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe] event System.Action E { add { } remove { } }
[System.Runtime.CompilerServices.RequiresUnsafe] int this[int i] { get => i; set { } }
[System.Runtime.CompilerServices.RequiresUnsafe] C() { }
[System.Runtime.CompilerServices.RequiresUnsafe] public static C operator +(C c1, C c2) => c1;
[System.Runtime.CompilerServices.RequiresUnsafe] public void operator +=(C c) { }
#pragma warning disable CS0169 // unused field
[System.Runtime.CompilerServices.RequiresUnsafe] int F;
}
[System.Runtime.CompilerServices.RequiresUnsafe] class U;
[System.Runtime.CompilerServices.RequiresUnsafe] delegate void D();
""",
CompilerFeatureRequiredAttribute,
"""
namespace System.Runtime.CompilerServices
{
public sealed class RequiresUnsafeAttribute : Attribute;
}
""",
];
string[] safeSymbols = ["C", "C.F", "U", "D"];
string[] unsafeSymbols =
[
"Program.<<Main>$>g__F|0_0",
"C.M",
"C.P", "C.get_P", "C.set_P",
"C.E", "C.add_E", "C.remove_E",
"C.this[]", "C.get_Item", "C.set_Item",
"C..ctor",
"C.op_Addition",
"C.op_AdditionAssignment",
];
string[] symbolsWithAttribute = safeSymbols.Except(["C"]).Concat(unsafeSymbols).ToArray();
CompileAndVerify(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All)
.WithSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules), ReportDiagnostic.Suppress),
symbolValidator: m =>
{
VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false);
VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [],
expectedSafeSymbols: [.. safeSymbols, .. unsafeSymbols],
expectedAttribute: symbolsWithAttribute);
})
.VerifyDiagnostics();
CompileAndVerify(source,
parseOptions: TestOptions.RegularPreview,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m =>
{
VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true);
VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [.. unsafeSymbols],
expectedSafeSymbols: [.. safeSymbols],
expectedAttribute: symbolsWithAttribute);
})
.VerifyDiagnostics();
CreateCompilation(source,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,2): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] void F() { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(2, 2),
// (5,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] void M() { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(5, 6),
// (6,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] int P { get; set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(6, 6),
// (8,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] event System.Action E { add { } remove { } }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(8, 6),
// (9,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] int this[int i] { get => i; set { } }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(9, 6),
// (10,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] C() { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(10, 6),
// (11,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] public static C operator +(C c1, C c2) => c1;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(11, 6),
// (12,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe] public void operator +=(C c) { }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(12, 6));
}
[Theory, CombinatorialData]
public void Member_Method_Invocation(
bool apiUpdatedRules,
bool apiUnsafe,
[CombinatorialValues(LanguageVersion.CSharp14, LanguageVersionFacts.CSharpNext, LanguageVersion.Preview)] LanguageVersion callerLangVersion,
bool callerAllowUnsafe,
bool callerUpdatedRules,
bool callerUnsafeBlock,
bool? compilationReference)
{
var requiresUnsafeAttribute = apiUnsafe && apiUpdatedRules
? "[System.Runtime.CompilerServices.RequiresUnsafe]"
: "";
var api = $$"""
public class C
{
{{requiresUnsafeAttribute}}
public void M() => System.Console.Write(111);
}
""";
var caller = $"""
var c = new C();
{(callerUnsafeBlock ? "unsafe { c.M(); }" : "c.M();")}
""";
var expectedOutput = "111";
CSharpCompilation comp;
List<DiagnosticDescription> expectedDiagnostics = [];
if (compilationReference is { } useCompilationReference)
{
var apiCompilation = CreateCompilation(
[api, .. (apiUnsafe && apiUpdatedRules ? new[] { RequiresUnsafeAttributeDefinition } : [])],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules(apiUpdatedRules))
.VerifyDiagnostics();
var apiReference = AsReference(apiCompilation, useCompilationReference);
comp = CreateCompilation(caller, [apiReference],
parseOptions: TestOptions.Regular.WithLanguageVersion(callerLangVersion),
options: TestOptions.ReleaseExe.WithAllowUnsafe(callerAllowUnsafe).WithUpdatedMemorySafetyRules(callerUpdatedRules));
}
else
{
if (apiUpdatedRules != callerUpdatedRules)
{
return;
}
comp = CreateCompilation(
[api, caller, .. (apiUnsafe && apiUpdatedRules ? new[] { RequiresUnsafeAttributeDefinition } : [])],
parseOptions: TestOptions.Regular.WithLanguageVersion(callerLangVersion),
options: TestOptions.ReleaseExe.WithAllowUnsafe(callerAllowUnsafe).WithUpdatedMemorySafetyRules(callerUpdatedRules));
}
if (!callerAllowUnsafe && callerUnsafeBlock)
{
expectedDiagnostics.Add(
// (2,1): error CS0227: Unsafe code may only appear if compiling with /unsafe
// unsafe { c.M(); }
Diagnostic(ErrorCode.ERR_IllegalUnsafe, "unsafe").WithLocation(2, 1));
}
if (apiUnsafe && apiUpdatedRules && callerUpdatedRules && !callerUnsafeBlock)
{
if (callerLangVersion >= LanguageVersionFacts.CSharpNext)
{
expectedDiagnostics.Add(
// (2,1): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M()").WithArguments("C.M()").WithLocation(2, 1));
}
else
{
expectedDiagnostics.Add(
// (2,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// c.M();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "c.M()").WithArguments("updated memory safety rules").WithLocation(2, 1));
}
}
// When compiling API and caller together (no compilationReference), the [RequiresUnsafe] attribute
// in source also triggers FeatureInPreview if using older language version
if (compilationReference is null && apiUnsafe && apiUpdatedRules && callerLangVersion < LanguageVersionFacts.CSharpNext)
{
expectedDiagnostics.Add(
// (3,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(3, 6));
}
comp.VerifyDiagnostics([.. expectedDiagnostics]);
if (!comp.GetDiagnostics().HasAnyErrors())
{
CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
}
}
[Fact]
public void Member_Method_OverloadResolution()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public static void M() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public static void M(int x) { }
}
""",
caller: """
C.M();
C.M(1);
_ = nameof(C.M);
unsafe { C.M(1); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: [Overload("C.M", 1)],
expectedSafeSymbols: ["C", Overload("C.M", 0)],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.M(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.M(1);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M(1)").WithArguments("C.M(int)").WithLocation(2, 1),
]);
}
[Fact]
public void Member_Method_SafeBoundary()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public void M1() { unsafe { M2(); } }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2() { }
}
""",
caller: """
var c = new C();
c.M1();
c.M2();
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.M2"],
expectedSafeSymbols: ["C.M1"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M2()").WithArguments("C.M2()").WithLocation(3, 1),
]);
}
[Fact]
public void Member_Method_NameOf()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static void M() { }
}
""",
caller: """
_ = nameof(C.M);
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedDiagnostics: []);
}
[Fact]
public void Member_Method_Extension()
{
CompileAndVerifyUnsafe(
lib: """
public static class E
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static void M1(this int x) { }
extension(int x)
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2() { }
}
}
""",
caller: """
123.M1();
123.M2();
E.M1(123);
E.M2(123);
unsafe { 123.M1(); }
unsafe { 123.M2(); }
unsafe { E.M1(123); }
unsafe { E.M2(123); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["E.M1", "E.M2", ExtensionMember("E", "M2")],
expectedSafeSymbols: [],
expectedDiagnostics:
[
// (1,1): error CS9362: 'E.M1(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// 123.M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "123.M1()").WithArguments("E.M1(int)").WithLocation(1, 1),
// (2,1): error CS9362: 'E.extension(int).M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// 123.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "123.M2()").WithArguments("E.extension(int).M2()").WithLocation(2, 1),
// (3,1): error CS9362: 'E.M1(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E.M1(123);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E.M1(123)").WithArguments("E.M1(int)").WithLocation(3, 1),
// (4,1): error CS9362: 'E.M2(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E.M2(123);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E.M2(123)").WithArguments("E.M2(int)").WithLocation(4, 1),
]);
}
[Fact]
public void Member_Method_InUnsafeClass()
{
CompileAndVerifyUnsafe(
lib: """
using System.Collections.Generic;
public unsafe class C
{
public void M1() { }
public IEnumerable<int> M2()
{
yield return 1;
}
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M3() { }
}
""",
caller: """
var c = new C();
c.M1();
c.M2();
c.M3();
unsafe { c.M3(); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.M3"],
expectedSafeSymbols: ["C.M1", "C.M2"],
expectedDiagnostics:
[
// (4,1): error CS9362: 'C.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M3();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M3()").WithArguments("C.M3()").WithLocation(4, 1),
]);
}
[Fact]
public void Member_Method_ConvertToFunctionPointer()
{
CompileAndVerifyUnsafe(
lib: """
public static class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static void M() { }
}
""",
caller: """
delegate*<void> p1 = &C.M;
unsafe { delegate*<void> p2 = &C.M; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,22): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// delegate*<void> p1 = &C.M;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "&C.M").WithArguments("C.M()").WithLocation(1, 22),
],
expectedDiagnosticsForLegacyCaller:
[
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// delegate*<void> p1 = &C.M;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(1, 1),
]);
}
[Fact]
public void Member_Method_ConvertToDelegate()
{
// https://github.com/dotnet/roslyn/issues/82546: confirm with LDM that delegates cannot be marked caller-unsafe;
// then unsafe modifier on a delegate should result in a warning
CompileAndVerifyUnsafe(
lib: """
public static class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static void M() { }
}
""",
caller: """
D1 a = C.M;
D2 b = C.M;
unsafe { D1 c = C.M; }
unsafe { D1 d = C.M; }
delegate void D1();
unsafe delegate void D2();
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,8): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// D1 a = C.M;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M").WithArguments("C.M()").WithLocation(1, 8),
// (2,8): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// D2 b = C.M;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M").WithArguments("C.M()").WithLocation(2, 8),
]);
}
[Fact]
public void Member_Method_Attribute()
{
var commonDiagnostics = new[]
{
// (3,4): error CS0617: 'F' is not a valid named attribute argument. Named attribute arguments must be fields which are not readonly, static, or const, or read-write properties which are public and not static.
// [A(F = 0)] void M2() { }
Diagnostic(ErrorCode.ERR_BadNamedAttributeArgument, "F").WithArguments("F").WithLocation(3, 4),
// (4,13): error CS0617: 'F' is not a valid named attribute argument. Named attribute arguments must be fields which are not readonly, static, or const, or read-write properties which are public and not static.
// unsafe { [A(F = 0)] void M3() { } }
Diagnostic(ErrorCode.ERR_BadNamedAttributeArgument, "F").WithArguments("F").WithLocation(4, 13),
// (5,4): error CS0617: 'F' is not a valid named attribute argument. Named attribute arguments must be fields which are not readonly, static, or const, or read-write properties which are public and not static.
// [A(F = 0)] unsafe void M4() { }
Diagnostic(ErrorCode.ERR_BadNamedAttributeArgument, "F").WithArguments("F").WithLocation(5, 4),
};
CompileAndVerifyUnsafe(
lib: """
public class A : System.Attribute
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void F(int x) { }
}
""",
caller: """
#pragma warning disable CS8321 // unused local function
[A] void M1() { }
[A(F = 0)] void M2() { }
unsafe { [A(F = 0)] void M3() { } }
[A(F = 0)] unsafe void M4() { }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["A.F"],
expectedSafeSymbols: ["A"],
expectedDiagnostics:
[
// (3,4): error CS9362: 'A.F(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [A(F = 0)] void M2() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "F = 0").WithArguments("A.F(int)").WithLocation(3, 4),
.. commonDiagnostics,
],
expectedDiagnosticsWhenReferencingLegacyLib: commonDiagnostics,
expectedDiagnosticsForLegacyCaller: commonDiagnostics);
}
[Fact]
public void Member_Method_Interface()
{
CompileAndVerifyUnsafe(
lib: """
public interface I
{
void M1();
[System.Runtime.CompilerServices.RequiresUnsafe]
void M2();
}
""",
caller: """
I i = null;
i.M1();
i.M2();
unsafe { i.M2(); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["I.M2"],
expectedSafeSymbols: ["I", "I.M1"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'I.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i.M2()").WithArguments("I.M2()").WithLocation(3, 1),
]);
}
[Fact]
public void Member_Method_Override_LangVersion()
{
var lib = """
public class B
{
public virtual void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual void M2() { }
}
""";
var caller = """
new C().M1();
class C : B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M1() { }
public override void M2() { }
}
""";
var expectedDiagnostics = new[]
{
// (1,1): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// new C().M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C().M1()").WithArguments("C.M1()").WithLocation(1, 1),
// (6,26): error CS9364: Unsafe member 'C.M1()' cannot override safe member 'B.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C.M1()", "B.M1()").WithLocation(6, 26),
};
CompileAndVerifyUnsafe(
lib: lib,
caller: caller,
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B.M2"],
expectedSafeSymbols: ["B.M1"],
expectedDiagnostics: expectedDiagnostics,
expectedDiagnosticsWhenReferencingLegacyLib: expectedDiagnostics);
CreateCompilation([lib, caller, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(4, 6),
// (5,6): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.Runtime.CompilerServices.RequiresUnsafe").WithArguments("updated memory safety rules").WithLocation(5, 6),
// (6,26): error CS9364: Unsafe member 'C.M1()' cannot override safe member 'B.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C.M1()", "B.M1()").WithLocation(6, 26),
// (1,1): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// new C().M1();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "new C().M1()").WithArguments("updated memory safety rules").WithLocation(1, 1));
}
[Fact]
public void Member_Method_Override()
{
CompileAndVerifyUnsafe(
lib: """
public class B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual void M2() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual void M3() { }
public virtual void M4() { }
public virtual void M5() { }
public virtual void M6() { }
}
public class C : B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M1() { }
public new virtual void M2() { }
public override void M3() { }
public override void M4() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public new virtual void M5() { }
}
""",
caller: """
var d1 = new D1(); d1.M1(); d1.M2(); d1.M3(); d1.M4(); d1.M5(); d1.M6();
var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
class D1 : C
{
public override void M1() { }
public override void M2() { }
public override void M3() { }
public override void M4() { }
public override void M5() { }
public override void M6() { }
public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M6(); }
}
class D2 : C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M2() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M3() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M4() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M5() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M6() { }
}
class D3 : C;
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B.M1", "B.M2", "B.M3", "C.M1", "C.M5"],
expectedSafeSymbols: ["B.M4", "B.M5", "B.M6", "C.M2", "C.M3", "C.M4"],
expectedDiagnostics:
[
// (2,20): error CS9362: 'D2.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M1()").WithArguments("D2.M1()").WithLocation(2, 20),
// (2,29): error CS9362: 'D2.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M2()").WithArguments("D2.M2()").WithLocation(2, 29),
// (2,38): error CS9362: 'D2.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M3()").WithArguments("D2.M3()").WithLocation(2, 38),
// (2,47): error CS9362: 'D2.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M4()").WithArguments("D2.M4()").WithLocation(2, 47),
// (2,56): error CS9362: 'D2.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M5()").WithArguments("D2.M5()").WithLocation(2, 56),
// (2,65): error CS9362: 'D2.M6()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M6()").WithArguments("D2.M6()").WithLocation(2, 65),
// (3,20): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M1()").WithArguments("C.M1()").WithLocation(3, 20),
// (3,56): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M5()").WithArguments("C.M5()").WithLocation(3, 56),
// (4,11): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M1()").WithArguments("C.M1()").WithLocation(4, 11),
// (4,43): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M5()").WithArguments("C.M5()").WithLocation(4, 43),
// (14,31): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M1()").WithArguments("C.M1()").WithLocation(14, 31),
// (22,26): error CS9364: Unsafe member 'D2.M2()' cannot override safe member 'C.M2()'
// public override void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M2").WithArguments("D2.M2()", "C.M2()").WithLocation(22, 26),
// (26,26): error CS9364: Unsafe member 'D2.M4()' cannot override safe member 'B.M4()'
// public override void M4() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M4").WithArguments("D2.M4()", "B.M4()").WithLocation(26, 26),
// (30,26): error CS9364: Unsafe member 'D2.M6()' cannot override safe member 'B.M6()'
// public override void M6() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M6").WithArguments("D2.M6()", "B.M6()").WithLocation(30, 26),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (2,20): error CS9362: 'D2.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M1()").WithArguments("D2.M1()").WithLocation(2, 20),
// (2,29): error CS9362: 'D2.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M2()").WithArguments("D2.M2()").WithLocation(2, 29),
// (2,38): error CS9362: 'D2.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M3()").WithArguments("D2.M3()").WithLocation(2, 38),
// (2,47): error CS9362: 'D2.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M4()").WithArguments("D2.M4()").WithLocation(2, 47),
// (2,56): error CS9362: 'D2.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M5()").WithArguments("D2.M5()").WithLocation(2, 56),
// (2,65): error CS9362: 'D2.M6()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d2.M6()").WithArguments("D2.M6()").WithLocation(2, 65),
// (20,26): error CS9364: Unsafe member 'D2.M1()' cannot override safe member 'B.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("D2.M1()", "B.M1()").WithLocation(20, 26),
// (22,26): error CS9364: Unsafe member 'D2.M2()' cannot override safe member 'C.M2()'
// public override void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M2").WithArguments("D2.M2()", "C.M2()").WithLocation(22, 26),
// (24,26): error CS9364: Unsafe member 'D2.M3()' cannot override safe member 'B.M3()'
// public override void M3() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M3").WithArguments("D2.M3()", "B.M3()").WithLocation(24, 26),
// (26,26): error CS9364: Unsafe member 'D2.M4()' cannot override safe member 'B.M4()'
// public override void M4() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M4").WithArguments("D2.M4()", "B.M4()").WithLocation(26, 26),
// (28,26): error CS9364: Unsafe member 'D2.M5()' cannot override safe member 'C.M5()'
// public override void M5() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M5").WithArguments("D2.M5()", "C.M5()").WithLocation(28, 26),
// (30,26): error CS9364: Unsafe member 'D2.M6()' cannot override safe member 'B.M6()'
// public override void M6() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M6").WithArguments("D2.M6()", "B.M6()").WithLocation(30, 26),
]);
}
[Fact]
public void Member_Method_Override_Metadata()
{
// [module: MemorySafetyRules(updated)]
// public class A
// {
// public virtual void M() { }
// }
// public class B : A
// {
// [RequiresUnsafe]
// public override void M() { }
// }
var refA = CompileIL($$"""
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{CSharpCompilationOptions.UpdatedMemorySafetyRulesVersion}}) }
.class public System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class public System.Runtime.CompilerServices.RequiresUnsafeAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public A
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
.method public hidebysig newslot virtual instance void M() cil managed { ret }
}
.class public B extends A
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
.method public hidebysig virtual instance void M() cil managed
{
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor()
ret
}
}
""",
prependDefaultHeader: false);
var moduleA = CreateCompilation("", [refA]).GetReferencedAssemblySymbol(refA).Modules.Single();
VerifyMemorySafetyRulesAttribute(
moduleA,
includesAttributeDefinition: true,
isSynthesized: false,
includesAttributeUse: true);
VerifyRequiresUnsafeAttribute(
moduleA,
expectedUnsafeSymbols: ["B.M"],
expectedSafeSymbols: ["A", "A.M", "B"]);
CreateCompilation("""
var c1 = new C1();
c1.M();
var c2 = new C2();
c2.M();
B b = c2;
b.M();
A a = b;
a.M();
class C1 : B
{
public override void M() { }
}
class C2 : B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M() { }
}
""",
[refA],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,1): error CS9362: 'C2.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c2.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c2.M()").WithArguments("C2.M()").WithLocation(4, 1),
// (6,1): error CS9362: 'B.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// b.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "b.M()").WithArguments("B.M()").WithLocation(6, 1),
// (17,26): error CS9364: Unsafe member 'C2.M()' cannot override safe member 'A.M()'
// public override void M() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M").WithArguments("C2.M()", "A.M()").WithLocation(17, 26));
}
[Fact]
public void Member_Method_Implementation()
{
CompileAndVerifyUnsafe(
lib: """
public interface I1
{
[System.Runtime.CompilerServices.RequiresUnsafe]
void M1();
void M2();
}
public interface I2
{
void M1();
[System.Runtime.CompilerServices.RequiresUnsafe]
void M2();
}
public class C1 : I1
{
public void M1() { }
public void M2() { }
}
public class C2 : I1
{
void I1.M1() { }
void I1.M2() { }
}
""",
caller: """
var c5 = new C5();
I1 i1 = c5;
i1.M1();
i1.M2();
I2 i2 = c5;
i2.M1();
i2.M2();
public class C3 : I1
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2() { }
}
public class C4 : I1
{
[System.Runtime.CompilerServices.RequiresUnsafe]
void I1.M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
void I1.M2() { }
}
public class C5 : I1, I2
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2() { }
}
public class C6 : I2, I1
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2() { }
}
public class C7 : I1, I2
{
public void M1() { }
public void M2() { }
}
public class C8 : I2, I1
{
public void M1() { }
public void M2() { }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["I1.M1", "I2.M2"],
expectedSafeSymbols: ["I1.M2", "I2.M1", "C1.M1", "C1.M2", "C2.I1.M1", "C2.I1.M2"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'I1.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i1.M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i1.M1()").WithArguments("I1.M1()").WithLocation(3, 1),
// (7,1): error CS9362: 'I2.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i2.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i2.M2()").WithArguments("I2.M2()").WithLocation(7, 1),
// (14,17): error CS9365: Unsafe member 'C3.M2()' cannot implicitly implement safe member 'I1.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C3.M2()", "I1.M2()").WithLocation(14, 17),
// (22,13): error CS9366: Unsafe member 'C4.I1.M2()' cannot implement safe member 'I1.M2()'
// void I1.M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeExplicitlyImplementingSafe, "M2").WithArguments("C4.I1.M2()", "I1.M2()").WithLocation(22, 13),
// (28,17): error CS9365: Unsafe member 'C5.M1()' cannot implicitly implement safe member 'I2.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C5.M1()", "I2.M1()").WithLocation(28, 17),
// (30,17): error CS9365: Unsafe member 'C5.M2()' cannot implicitly implement safe member 'I1.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C5.M2()", "I1.M2()").WithLocation(30, 17),
// (36,17): error CS9365: Unsafe member 'C6.M1()' cannot implicitly implement safe member 'I2.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C6.M1()", "I2.M1()").WithLocation(36, 17),
// (38,17): error CS9365: Unsafe member 'C6.M2()' cannot implicitly implement safe member 'I1.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C6.M2()", "I1.M2()").WithLocation(38, 17),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (12,17): error CS9365: Unsafe member 'C3.M1()' cannot implicitly implement safe member 'I1.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C3.M1()", "I1.M1()").WithLocation(12, 17),
// (14,17): error CS9365: Unsafe member 'C3.M2()' cannot implicitly implement safe member 'I1.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C3.M2()", "I1.M2()").WithLocation(14, 17),
// (20,13): error CS9366: Unsafe member 'C4.I1.M1()' cannot implement safe member 'I1.M1()'
// void I1.M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeExplicitlyImplementingSafe, "M1").WithArguments("C4.I1.M1()", "I1.M1()").WithLocation(20, 13),
// (22,13): error CS9366: Unsafe member 'C4.I1.M2()' cannot implement safe member 'I1.M2()'
// void I1.M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeExplicitlyImplementingSafe, "M2").WithArguments("C4.I1.M2()", "I1.M2()").WithLocation(22, 13),
// (28,17): error CS9365: Unsafe member 'C5.M1()' cannot implicitly implement safe member 'I1.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C5.M1()", "I1.M1()").WithLocation(28, 17),
// (28,17): error CS9365: Unsafe member 'C5.M1()' cannot implicitly implement safe member 'I2.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C5.M1()", "I2.M1()").WithLocation(28, 17),
// (30,17): error CS9365: Unsafe member 'C5.M2()' cannot implicitly implement safe member 'I1.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C5.M2()", "I1.M2()").WithLocation(30, 17),
// (30,17): error CS9365: Unsafe member 'C5.M2()' cannot implicitly implement safe member 'I2.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C5.M2()", "I2.M2()").WithLocation(30, 17),
// (36,17): error CS9365: Unsafe member 'C6.M1()' cannot implicitly implement safe member 'I2.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C6.M1()", "I2.M1()").WithLocation(36, 17),
// (36,17): error CS9365: Unsafe member 'C6.M1()' cannot implicitly implement safe member 'I1.M1()'
// public void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C6.M1()", "I1.M1()").WithLocation(36, 17),
// (38,17): error CS9365: Unsafe member 'C6.M2()' cannot implicitly implement safe member 'I2.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C6.M2()", "I2.M2()").WithLocation(38, 17),
// (38,17): error CS9365: Unsafe member 'C6.M2()' cannot implicitly implement safe member 'I1.M2()'
// public void M2() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C6.M2()", "I1.M2()").WithLocation(38, 17),
]);
}
[Fact]
public void Member_Method_Implementation_Synthesized()
{
CompileAndVerifyUnsafe(
lib: """
public class B<T>
{
public void M1(T x) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2(T x) { }
}
""",
caller: """
var c = new C();
c.M1(null);
c.M2(null);
class C : B<D>, I;
class D;
interface I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
void M1(D x);
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B.M2"],
expectedSafeSymbols: ["B.M1"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'B<D>.M2(D)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M2(null)").WithArguments("B<D>.M2(D)").WithLocation(3, 1),
]);
}
[Fact]
public void Member_Method_OverrideOfImplementation()
{
CompileAndVerifyUnsafe(
lib: """
public interface I
{
void M1();
[System.Runtime.CompilerServices.RequiresUnsafe]
void M2();
}
public class B1 : I
{
public virtual void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual void M2() { }
}
""",
caller: """
var c1 = new C1();
c1.M1();
c1.M2();
B1 b1 = c1;
b1.M1();
b1.M2();
I i = b1;
i.M1();
i.M2();
class B2 : I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual void M1() { }
public virtual void M2() { }
}
class C1 : B1
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M1() { }
public override void M2() { }
}
class C2 : B1, I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override void M1() { }
public override void M2() { }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["I.M2", "B1.M2"],
expectedSafeSymbols: ["I.M1", "B1.M1"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C1.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c1.M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c1.M1()").WithArguments("C1.M1()").WithLocation(2, 1),
// (6,1): error CS9362: 'B1.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// b1.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "b1.M2()").WithArguments("B1.M2()").WithLocation(6, 1),
// (9,1): error CS9362: 'I.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i.M2()").WithArguments("I.M2()").WithLocation(9, 1),
// (14,25): error CS9365: Unsafe member 'B2.M1()' cannot implicitly implement safe member 'I.M1()'
// public virtual void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("B2.M1()", "I.M1()").WithLocation(14, 25),
// (21,26): error CS9364: Unsafe member 'C1.M1()' cannot override safe member 'B1.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C1.M1()", "B1.M1()").WithLocation(21, 26),
// (28,26): error CS9364: Unsafe member 'C2.M1()' cannot override safe member 'B1.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C2.M1()", "B1.M1()").WithLocation(28, 26),
// (28,26): error CS9365: Unsafe member 'C2.M1()' cannot implicitly implement safe member 'I.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C2.M1()", "I.M1()").WithLocation(28, 26),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (2,1): error CS9362: 'C1.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c1.M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c1.M1()").WithArguments("C1.M1()").WithLocation(2, 1),
// (14,25): error CS9365: Unsafe member 'B2.M1()' cannot implicitly implement safe member 'I.M1()'
// public virtual void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("B2.M1()", "I.M1()").WithLocation(14, 25),
// (21,26): error CS9364: Unsafe member 'C1.M1()' cannot override safe member 'B1.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C1.M1()", "B1.M1()").WithLocation(21, 26),
// (28,26): error CS9364: Unsafe member 'C2.M1()' cannot override safe member 'B1.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C2.M1()", "B1.M1()").WithLocation(28, 26),
// (28,26): error CS9365: Unsafe member 'C2.M1()' cannot implicitly implement safe member 'I.M1()'
// public override void M1() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C2.M1()", "I.M1()").WithLocation(28, 26),
]);
}
/// <summary>
/// Caller-unsafety should not count as part of the signature for hiding purposes.
/// </summary>
[Fact]
public void Member_Method_Hiding()
{
DiagnosticDescription[] commonDiagnostics =
[
// (7,17): warning CS0108: 'C1.M1()' hides inherited member 'B.M1()'. Use the new keyword if hiding was intended.
// public void M1() { }
Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("C1.M1()", "B.M1()").WithLocation(7, 17),
// (9,17): warning CS0108: 'C1.M2()' hides inherited member 'B.M2()'. Use the new keyword if hiding was intended.
// public void M2() { }
Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("C1.M2()", "B.M2()").WithLocation(9, 17),
// (16,17): error CS0111: Type 'C2' already defines a member called 'M1' with the same parameter types
// public void M1() { }
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C2").WithLocation(16, 17),
];
DiagnosticDescription[] updatedCallerDiagnostics =
[
// (3,1): error CS9362: 'C1.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M2()").WithArguments("C1.M2()").WithLocation(3, 1),
.. commonDiagnostics,
];
CompileAndVerifyUnsafe(
lib: """
public class B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M1() { }
public void M2() { }
}
""",
caller: """
var c = new C1();
c.M1();
c.M2();
class C1 : B
{
public void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M2() { }
}
class C2
{
public void M1() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M1() { }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B.M1"],
expectedSafeSymbols: ["B.M2"],
expectedDiagnostics: updatedCallerDiagnostics,
expectedDiagnosticsWhenReferencingLegacyLib: updatedCallerDiagnostics,
expectedDiagnosticsForLegacyCaller: commonDiagnostics);
}
[Fact]
public void Member_Await()
{
static string getLib(string onCompletedAttribute) => $$"""
using System;
using System.Runtime.CompilerServices;
public class C : INotifyCompletion
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public bool IsCompleted => false;
[System.Runtime.CompilerServices.RequiresUnsafe]
public C GetAwaiter() => this;
[System.Runtime.CompilerServices.RequiresUnsafe]
public void GetResult() { }
{{onCompletedAttribute}}
public void OnCompleted(Action continuation) { }
}
""";
CreateCompilation(
[getLib("[System.Runtime.CompilerServices.RequiresUnsafe]"), RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (13,17): error CS9365: Unsafe member 'C.OnCompleted(Action)' cannot implicitly implement safe member 'INotifyCompletion.OnCompleted(Action)'
// public void OnCompleted(Action continuation) { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "OnCompleted").WithArguments("C.OnCompleted(System.Action)", "System.Runtime.CompilerServices.INotifyCompletion.OnCompleted(System.Action)").WithLocation(13, 17));
var lib = getLib("");
CompileAndVerifyUnsafe(
lib: lib,
caller: """
await new C();
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.IsCompleted", "C.GetAwaiter", "C.GetResult"],
expectedSafeSymbols: ["C", "C.OnCompleted"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C.GetAwaiter()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// await new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "await new C()").WithArguments("C.GetAwaiter()").WithLocation(1, 1),
// (1,1): error CS9362: 'C.IsCompleted.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// await new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "await new C()").WithArguments("C.IsCompleted.get").WithLocation(1, 1),
// (1,1): error CS9362: 'C.GetResult()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// await new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "await new C()").WithArguments("C.GetResult()").WithLocation(1, 1),
]);
CreateCompilation(
[
lib,
RequiresUnsafeAttributeDefinition,
"""
unsafe { await new C(); }
""",
],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,10): error CS4004: Cannot await in an unsafe context
// unsafe { await new C(); }
Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await new C()").WithLocation(1, 10));
}
[Fact]
public void Member_AsyncHelpers()
{
var corlib = CreateEmptyCompilation(
"""
namespace System
{
public class Object;
public class ValueType;
public class Attribute;
public struct Void;
public struct Int32;
public struct Boolean;
public class AttributeUsageAttribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public class Enum;
public enum AttributeTargets;
public class String;
public class Action;
}
namespace System.Runtime.CompilerServices
{
public interface INotifyCompletion;
public static class AsyncHelpers
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static void AwaitAwaiter<TAwaiter>(TAwaiter awaiter) where TAwaiter : INotifyCompletion { }
}
public class RequiresUnsafeAttribute : Attribute { }
}
namespace System.Threading.Tasks
{
public class Task : System.Runtime.CompilerServices.INotifyCompletion
{
public bool IsCompleted => false;
public Task GetAwaiter() => this;
public void GetResult() { }
public void OnCompleted(Action continuation) { }
}
}
""",
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.EmitToImageReference();
CreateEmptyCompilation("""
using System.Threading.Tasks;
class Test
{
public static async Task F()
{
await new Task();
}
}
""",
[corlib],
parseOptions: WithRuntimeAsync(TestOptions.RegularPreview),
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (7,15): error CS9362: 'AsyncHelpers.AwaitAwaiter<Task>(Task)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// await new Task();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new Task()").WithArguments("System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter<System.Threading.Tasks.Task>(System.Threading.Tasks.Task)").WithLocation(7, 15));
CreateEmptyCompilation("""
using System.Threading.Tasks;
class Test
{
public static async Task F()
{
unsafe { await new Task(); }
}
}
""",
[corlib],
parseOptions: WithRuntimeAsync(TestOptions.RegularPreview),
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (7,18): error CS4004: Cannot await in an unsafe context
// unsafe { await new Task(); }
Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await new Task()").WithLocation(7, 18));
}
[Fact]
public void Member_CollectionBuilder_Create()
{
CompileAndVerifyUnsafe(
lib: """
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(C), nameof(Create))]
public class C : IEnumerable<int>
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static C Create(ReadOnlySpan<int> s) => new C();
public IEnumerator<int> GetEnumerator() => throw null;
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
""",
caller: """
C c1 = [1, 2, 3];
M(1, 2, 3);
static void M(params C c) { }
unsafe
{
C c2 = [1, 2, 3];
M2(1, 2, 3);
static void M2(params C c) { }
}
M3(1, 2, 3);
static unsafe void M3(params C c) { }
""",
additionalSources: [TestSources.Span, CollectionBuilderAttributeDefinition, RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.Create"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,8): error CS9362: 'C.Create(ReadOnlySpan<int>)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [1, 2, 3];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[1, 2, 3]").WithArguments("C.Create(System.ReadOnlySpan<int>)").WithLocation(1, 8),
// (2,1): error CS9362: 'C.Create(ReadOnlySpan<int>)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "M(1, 2, 3)").WithArguments("C.Create(System.ReadOnlySpan<int>)").WithLocation(2, 1),
// (3,15): error CS9362: 'C.Create(ReadOnlySpan<int>)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// static void M(params C c) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "params C c").WithArguments("C.Create(System.ReadOnlySpan<int>)").WithLocation(3, 15),
// (12,1): error CS9362: 'C.Create(ReadOnlySpan<int>)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M3(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "M3(1, 2, 3)").WithArguments("C.Create(System.ReadOnlySpan<int>)").WithLocation(12, 1),
]);
}
[Fact]
public void Member_CollectionBuilder_GetEnumerator()
{
CompileAndVerifyUnsafe(
lib: """
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(C), nameof(Create))]
public class C : IEnumerable<int>
{
public static C Create(ReadOnlySpan<int> s) => new C();
[System.Runtime.CompilerServices.RequiresUnsafe]
public IEnumerator<int> GetEnumerator() => null;
IEnumerator<int> IEnumerable<int>.GetEnumerator() => null;
IEnumerator IEnumerable.GetEnumerator() => null;
}
""",
caller: """
C c1 = [1, 2, 3];
M(1, 2, 3);
static void M(params C c) { }
""",
additionalSources: [TestSources.Span, CollectionBuilderAttributeDefinition, RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.GetEnumerator"],
expectedSafeSymbols: ["C", "C.Create"],
expectedDiagnostics: []);
}
[Fact]
public void Member_CollectionConstructor()
{
CompileAndVerifyUnsafe(
lib: """
using System.Collections;
using System.Collections.Generic;
public class C : IEnumerable<int>
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public C() { }
public void Add(int x) { }
public IEnumerator<int> GetEnumerator() => throw null;
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
""",
caller: """
C c1 = [1, 2, 3];
M1(1, 2, 3);
static void M1(params C c) { }
unsafe
{
C c2 = [1, 2, 3];
M2(1, 2, 3);
static void M2(params C c) { }
}
M3(1, 2, 3);
static unsafe void M3(params C c) { }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C..ctor"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,8): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [1, 2, 3];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[1, 2, 3]").WithArguments("C.C()").WithLocation(1, 8),
// (2,1): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M1(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "M1(1, 2, 3)").WithArguments("C.C()").WithLocation(2, 1),
// (3,16): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// static void M1(params C c) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "params C c").WithArguments("C.C()").WithLocation(3, 16),
// (12,1): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M3(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "M3(1, 2, 3)").WithArguments("C.C()").WithLocation(12, 1),
]);
}
[Fact]
public void Member_CollectionAddMethod()
{
CompileAndVerifyUnsafe(
lib: """
using System.Collections;
using System.Collections.Generic;
public class C : IEnumerable<int>
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void Add(int x) { }
public IEnumerator<int> GetEnumerator() => throw null;
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
""",
caller: """
C c1 = [1, 2, 3];
C c2 = new() { 1, 2, 3 };
C c3 = [.. new C()];
X x1 = new() { F = { 1, 2, 3 } };
M1(1, 2, 3);
static void M1(params C c) { }
unsafe
{
C c4 = [1, 2, 3];
C c5 = new() { 1, 2, 3 };
C c6 = [.. new C()];
X x2 = new() { F = { 1, 2, 3 } };
M2(1, 2, 3);
static void M2(params C c) { }
}
M3(1, 2, 3);
static unsafe void M3(params C c) { }
class X { public C F; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.Add"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,9): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [1, 2, 3];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "1").WithArguments("C.Add(int)").WithLocation(1, 9),
// (1,12): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [1, 2, 3];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "2").WithArguments("C.Add(int)").WithLocation(1, 12),
// (1,15): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [1, 2, 3];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "3").WithArguments("C.Add(int)").WithLocation(1, 15),
// (2,16): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c2 = new() { 1, 2, 3 };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "1").WithArguments("C.Add(int)").WithLocation(2, 16),
// (2,19): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c2 = new() { 1, 2, 3 };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "2").WithArguments("C.Add(int)").WithLocation(2, 19),
// (2,22): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c2 = new() { 1, 2, 3 };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "3").WithArguments("C.Add(int)").WithLocation(2, 22),
// (3,12): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c3 = [.. new C()];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C()").WithArguments("C.Add(int)").WithLocation(3, 12),
// (4,22): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// X x1 = new() { F = { 1, 2, 3 } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "1").WithArguments("C.Add(int)").WithLocation(4, 22),
// (4,25): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// X x1 = new() { F = { 1, 2, 3 } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "2").WithArguments("C.Add(int)").WithLocation(4, 25),
// (4,28): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// X x1 = new() { F = { 1, 2, 3 } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "3").WithArguments("C.Add(int)").WithLocation(4, 28),
// (5,4): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M1(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "1").WithArguments("C.Add(int)").WithLocation(5, 4),
// (5,7): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M1(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "2").WithArguments("C.Add(int)").WithLocation(5, 7),
// (5,10): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M1(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "3").WithArguments("C.Add(int)").WithLocation(5, 10),
// (6,16): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// static void M1(params C c) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "params C c").WithArguments("C.Add(int)").WithLocation(6, 16),
// (18,4): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M3(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "1").WithArguments("C.Add(int)").WithLocation(18, 4),
// (18,7): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M3(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "2").WithArguments("C.Add(int)").WithLocation(18, 7),
// (18,10): error CS9362: 'C.Add(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M3(1, 2, 3);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "3").WithArguments("C.Add(int)").WithLocation(18, 10),
]);
}
[Fact]
public void Member_GetEnumerator()
{
CompileAndVerifyUnsafe(
lib: """
using System.Collections;
using System.Collections.Generic;
public class C : IEnumerable<int>
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public IEnumerator<int> GetEnumerator() => null;
IEnumerator<int> IEnumerable<int>.GetEnumerator() => null;
IEnumerator IEnumerable.GetEnumerator() => null;
}
""",
caller: """
foreach (var c in new C()) { }
unsafe { foreach (var c in new C()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.GetEnumerator"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C.GetEnumerator()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var c in new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "foreach").WithArguments("C.GetEnumerator()").WithLocation(1, 1),
]);
}
[Fact]
public void Member_GetEnumerator_Spread()
{
CompileAndVerifyUnsafe(
lib: """
using System.Collections;
using System.Collections.Generic;
public class C : IEnumerable<int>
{
public void Add(int x) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public C GetEnumerator() => this;
[System.Runtime.CompilerServices.RequiresUnsafe]
public bool MoveNext() => false;
[System.Runtime.CompilerServices.RequiresUnsafe]
public int Current => 0;
IEnumerator<int> IEnumerable<int>.GetEnumerator() => null;
IEnumerator IEnumerable.GetEnumerator() => null;
}
""",
caller: """
C c1 = [.. new C()];
unsafe { C c2 = [.. new C()]; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.GetEnumerator", "C.MoveNext", "C.Current", "C.get_Current"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,9): error CS9362: 'C.GetEnumerator()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [.. new C()];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "..").WithArguments("C.GetEnumerator()").WithLocation(1, 9),
// (1,9): error CS9362: 'C.MoveNext()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [.. new C()];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "..").WithArguments("C.MoveNext()").WithLocation(1, 9),
// (1,9): error CS9362: 'C.Current.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c1 = [.. new C()];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "..").WithArguments("C.Current.get").WithLocation(1, 9),
]);
}
[Fact]
public void Member_MoveNext()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public C GetEnumerator() => this;
[System.Runtime.CompilerServices.RequiresUnsafe]
public bool MoveNext() => false;
public int Current => 0;
}
""",
caller: """
foreach (var x in new C()) { }
unsafe { foreach (var x in new C()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.MoveNext"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C.MoveNext()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var x in new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "foreach").WithArguments("C.MoveNext()").WithLocation(1, 1),
]);
}
[Theory]
[InlineData("=> 0;")]
[InlineData("{ get => 0; }")]
public void Member_Current_Property(string getter)
{
CompileAndVerifyUnsafe(
lib: $$"""
public class C
{
public C GetEnumerator() => this;
public bool MoveNext() => false;
[System.Runtime.CompilerServices.RequiresUnsafe]
public int Current {{getter}}
}
""",
caller: """
foreach (var x in new C()) { }
unsafe { foreach (var x in new C()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.Current", "C.get_Current"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C.Current.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var x in new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "foreach").WithArguments("C.Current.get").WithLocation(1, 1),
]);
}
[Fact]
public void Member_Current_Getter()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public C GetEnumerator() => this;
public bool MoveNext() => false;
public int Current { [System.Runtime.CompilerServices.RequiresUnsafe] get => 0; }
}
""",
caller: """
foreach (var x in new C()) { }
unsafe { foreach (var x in new C()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.get_Current"],
expectedSafeSymbols: ["C", "C.Current"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C.Current.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var x in new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "foreach").WithArguments("C.Current.get").WithLocation(1, 1),
]);
}
[Fact]
public void Member_Current_Setter()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public C GetEnumerator() => this;
public bool MoveNext() => false;
public int Current { get => 0; [System.Runtime.CompilerServices.RequiresUnsafe] set { } }
}
""",
caller: """
foreach (var x in new C()) { }
unsafe { foreach (var x in new C()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.set_Current"],
expectedSafeSymbols: ["C", "C.Current", "C.get_Current"],
expectedDiagnostics: []);
}
[Fact]
public void Member_Dispose_Class()
{
CreateCompilation(["""
public class C : System.IDisposable
{
public C GetEnumerator() => this;
public bool MoveNext() => false;
public int Current => 0;
[System.Runtime.CompilerServices.RequiresUnsafe]
public void Dispose() { }
}
""", RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (7,17): error CS9365: Unsafe member 'C.Dispose()' cannot implicitly implement safe member 'IDisposable.Dispose()'
// public unsafe void Dispose() { }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "Dispose").WithArguments("C.Dispose()", "System.IDisposable.Dispose()").WithLocation(7, 17));
}
[Fact]
public void Member_Dispose_Interface()
{
CompileAndVerifyUnsafe(
lib: """
public class C : System.IDisposable
{
public C GetEnumerator() => this;
public bool MoveNext() => false;
public int Current => 0;
public void Dispose() { }
}
namespace System
{
public class Object;
public class ValueType;
public class Attribute;
public struct Void;
public struct Int32;
public struct Boolean;
public class AttributeUsageAttribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public class String;
public class Enum;
public enum AttributeTargets;
public interface IDisposable
{
[System.Runtime.CompilerServices.RequiresUnsafe]
void Dispose();
}
}
namespace System.Runtime.CompilerServices
{
public class CompilerGeneratedAttribute;
public class RequiresUnsafeAttribute : Attribute;
}
namespace System.Collections
{
public interface IEnumerable;
}
namespace System.Collections.Generic
{
public interface IEnumerable<T> : IEnumerable;
public class List<T> : IEnumerable<T>
{
public void Add(T element) { }
}
}
""",
caller: """
foreach (var x in new C()) { }
using (var c = new C()) { }
System.Collections.Generic.List<int> l = [.. new C()];
unsafe { foreach (var x in new C()) { } }
unsafe { using (var c = new C()) { } }
unsafe { System.Collections.Generic.List<int> l2 = [.. new C()]; }
""",
targetFramework: TargetFramework.Empty,
optionsDll: TestOptions.UnsafeDebugDll
// warning CS8021: No value for RuntimeMetadataVersion found
.WithSpecificDiagnosticOptions(GetIdForErrorCode(ErrorCode.WRN_NoRuntimeMetadataVersion), ReportDiagnostic.Suppress),
expectedUnsafeSymbols: ["System.IDisposable.Dispose"],
expectedSafeSymbols: ["C", "C.Dispose", "System.IDisposable"],
verify: Verification.FailsPEVerify,
expectedDiagnostics:
[
// (1,1): error CS9362: 'IDisposable.Dispose()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var x in new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "foreach").WithArguments("System.IDisposable.Dispose()").WithLocation(1, 1),
// (2,8): error CS9362: 'IDisposable.Dispose()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// using (var c = new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "var c = new C()").WithArguments("System.IDisposable.Dispose()").WithLocation(2, 8),
// (3,43): error CS9362: 'IDisposable.Dispose()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// System.Collections.Generic.List<int> l = [.. new C()];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "..").WithArguments("System.IDisposable.Dispose()").WithLocation(3, 43),
]);
}
[Fact]
public void Member_Dispose_RefStruct()
{
CompileAndVerifyUnsafe(
lib: """
public ref struct S
{
public S GetEnumerator() => this;
public bool MoveNext() => false;
public int Current => 0;
[System.Runtime.CompilerServices.RequiresUnsafe]
public void Dispose() { }
}
""",
caller: """
foreach (var x in new S()) { }
using (var s = new S()) { }
unsafe { foreach (var y in new S()) { } }
unsafe { using (var s = new S()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["S.Dispose"],
expectedSafeSymbols: ["S"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'S.Dispose()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var x in new S()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "foreach (var x in new S()) { }").WithArguments("S.Dispose()").WithLocation(1, 1),
// (2,8): error CS9362: 'S.Dispose()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// using (var s = new S()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "var s = new S()").WithArguments("S.Dispose()").WithLocation(2, 8),
]);
}
[Fact]
public void Member_DisposeAsync()
{
CompileAndVerifyUnsafe(
lib: """
using System.Threading.Tasks;
public class C
{
public C GetAsyncEnumerator() => this;
public Task<bool> MoveNextAsync() => null;
public int Current => 0;
[System.Runtime.CompilerServices.RequiresUnsafe]
public Task DisposeAsync() => null;
}
""",
caller: """
await foreach (var x in new C()) { }
await using (var c = new C()) { }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.DisposeAsync"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C.DisposeAsync()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// await foreach (var x in new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "await foreach (var x in new C()) { }").WithArguments("C.DisposeAsync()").WithLocation(1, 1),
// (2,14): error CS9362: 'C.DisposeAsync()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// await using (var c = new C()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "var c = new C()").WithArguments("C.DisposeAsync()").WithLocation(2, 14),
]);
}
[Fact]
public void Member_GetPinnableReference()
{
CompileAndVerifyUnsafe(
lib: """
public class C1 { public ref int GetPinnableReference() => throw null; }
public class C2 { [System.Runtime.CompilerServices.RequiresUnsafe] public ref int GetPinnableReference() => throw null; }
""",
caller: """
fixed (int* p = new C1()) { }
fixed (int* p = new C2()) { }
unsafe { fixed (int* p = new C2()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C2.GetPinnableReference"],
expectedSafeSymbols: ["C1", "C1.GetPinnableReference", "C2"],
expectedDiagnostics:
[
// (2,17): error CS9362: 'C2.GetPinnableReference()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// fixed (int* p = new C2()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C2()").WithArguments("C2.GetPinnableReference()").WithLocation(2, 17),
],
expectedDiagnosticsForLegacyCaller:
[
// (1,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = new C1()) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "fixed (int* p = new C1()) { }").WithLocation(1, 1),
// (1,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = new C1()) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 8),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = new C2()) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "fixed (int* p = new C2()) { }").WithLocation(2, 1),
// (2,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed (int* p = new C2()) { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 8),
]);
}
[Fact]
public void Member_Deconstruct()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void Deconstruct(out int x, out int y) { x = y = 0; }
}
""",
caller: """
var (x, y) = new C();
unsafe { var (a, b) = new C(); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.Deconstruct"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,14): error CS9362: 'C.Deconstruct(out int, out int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var (x, y) = new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C()").WithArguments("C.Deconstruct(out int, out int)").WithLocation(1, 14),
]);
}
[Fact]
public void Member_LockObject()
{
CompileAndVerifyUnsafe(
lib: """
namespace System.Threading;
public class Lock
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public Scope EnterScope() => new();
public ref struct Scope
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void Dispose() { }
}
}
""",
caller: """
lock (new System.Threading.Lock()) { }
unsafe { lock (new System.Threading.Lock()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["System.Threading.Lock.EnterScope", "System.Threading.Lock.Scope.Dispose"],
expectedSafeSymbols: ["System.Threading.Lock", "System.Threading.Lock.Scope"],
expectedDiagnostics:
[
// (1,7): error CS9362: 'Lock.EnterScope()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// lock (new System.Threading.Lock()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new System.Threading.Lock()").WithArguments("System.Threading.Lock.EnterScope()").WithLocation(1, 7),
// (1,7): error CS9362: 'Lock.Scope.Dispose()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// lock (new System.Threading.Lock()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new System.Threading.Lock()").WithArguments("System.Threading.Lock.Scope.Dispose()").WithLocation(1, 7),
]);
}
[Fact]
public void Member_ITuple()
{
CompileAndVerifyUnsafe(
lib: """
namespace System.Runtime.CompilerServices;
public interface ITuple
{
[System.Runtime.CompilerServices.RequiresUnsafe]
int Length { get; }
[System.Runtime.CompilerServices.RequiresUnsafe]
object this[int index] { get; }
}
""",
caller: """
object o = null;
_ = o is (int x, string y);
unsafe { _ = o is (int a, string b); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["System.Runtime.CompilerServices.ITuple.Length", "System.Runtime.CompilerServices.ITuple.get_Length", "System.Runtime.CompilerServices.ITuple.this[]", "System.Runtime.CompilerServices.ITuple.get_Item"],
expectedSafeSymbols: ["System.Runtime.CompilerServices.ITuple"],
expectedDiagnostics:
[
// (2,10): error CS9362: 'ITuple.Length.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = o is (int x, string y);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "(int x, string y)").WithArguments("System.Runtime.CompilerServices.ITuple.Length.get").WithLocation(2, 10),
// (2,10): error CS9362: 'ITuple.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = o is (int x, string y);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "(int x, string y)").WithArguments("System.Runtime.CompilerServices.ITuple.this[int].get").WithLocation(2, 10),
]);
}
[Fact]
public void Member_InterpolatedStringHandler()
{
CompileAndVerifyUnsafe(
lib: """
[System.Runtime.CompilerServices.InterpolatedStringHandler]
public struct C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public C(int literalLength, int formattedCount) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void AppendLiteral(string s) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void AppendFormatted<T>(T t) { }
}
""",
caller: """
log($"a{0}");
unsafe { log($"a{0}"); };
void log(C c) { }
""",
additionalSources: [InterpolatedStringHandlerAttribute, RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: [Overload("C..ctor", parameterCount: 2), "C.AppendLiteral", "C.AppendFormatted"],
expectedSafeSymbols: ["C", Overload("C..ctor", parameterCount: 0)],
expectedDiagnostics:
[
// (1,7): error CS9362: 'C.AppendLiteral(string)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// log($"a{0}");
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "a").WithArguments("C.AppendLiteral(string)").WithLocation(1, 7),
// (1,8): error CS9362: 'C.AppendFormatted<int>(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// log($"a{0}");
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "{0}").WithArguments("C.AppendFormatted<int>(int)").WithLocation(1, 8),
// (1,5): error CS9362: 'C.C(int, int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// log($"a{0}");
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, @"$""a{0}""").WithArguments("C.C(int, int)").WithLocation(1, 5),
]);
}
[Theory, CombinatorialData]
public void Member_Interceptor(
[CombinatorialValues("[System.Runtime.CompilerServices.RequiresUnsafe]", "")] string unsafe1,
[CombinatorialValues("[System.Runtime.CompilerServices.RequiresUnsafe]", "")] string unsafe2)
{
var source = ($$"""
C.M();
class C
{
{{unsafe1}}
public static void M() { }
}
""", "Program.cs");
var comp = CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var interceptableLocation = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Select(node => model.GetInterceptableLocation(node)).Single()!;
var interceptor = ($$"""
class D
{
{{interceptableLocation.GetInterceptsLocationAttributeSyntax()}}
{{unsafe2}}
public static void M() => System.Console.Write(1);
}
""", "Interceptor.cs");
CreateCompilation([source, interceptor, (TestSources.InterceptsLocationAttribute, "Attribute.cs"), RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.RegularPreview.WithFeature(Feature.InterceptorsNamespaces, "global"),
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(unsafe1.Length > 0
? [
// Program.cs(1,1): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M()").WithArguments("C.M()").WithLocation(1, 1),
]
: []);
}
[Fact]
public void Member_Iterator()
{
var lib = """
using System.Collections.Generic;
public static class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static IEnumerable<int> M()
{
yield return 1;
}
}
""";
CompileAndVerifyUnsafe(
lib: lib,
caller: """
foreach (var x in C.M()) { }
unsafe { foreach (var y in C.M()) { } }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,19): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// foreach (var x in C.M()) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M()").WithArguments("C.M()").WithLocation(1, 19),
]);
// Test symbols that are only in PE image (hence cannot test them via the helper above).
var libRef = CreateCompilation(
[lib, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All))
.EmitToImageReference();
var libAssemblySymbol = CreateCompilation("", [libRef]).GetReferencedAssemblySymbol(libRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C", "C.<M>d__0", "C.<M>d__0.MoveNext"]);
}
[Fact]
public void Member_LocalFunction()
{
var source = """
M1();
M2();
unsafe { M1(); }
[System.Runtime.CompilerServices.RequiresUnsafe]
static void M1() { }
static void M2() { }
""";
CreateCompilation([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS9362: 'M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "M1()").WithArguments("M1()").WithLocation(1, 1));
}
[Fact]
public void Member_Lambda()
{
var source = """
var lam = [System.Runtime.CompilerServices.RequiresUnsafe] () => { };
lam();
""";
CreateCompilation([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,12): error CS9367: RequiresUnsafeAttribute cannot be applied to this symbol.
// var lam = [System.Runtime.CompilerServices.RequiresUnsafe] () => { };
Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeUnsupportedMemberTarget, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(1, 12));
}
[Fact]
public void Member_Lambda_InUnsafeContext()
{
var source = """
unsafe
{
D lam = () => { };
}
delegate void D();
""";
var metadata = CreateCompilation(source,
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.EmitToImageReference();
var assemblySymbol = CreateCompilation("", [metadata],
options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All))
.GetReferencedAssemblySymbol(metadata);
VerifyRequiresUnsafeAttribute(
assemblySymbol.Modules.Single(),
expectedUnsafeSymbols: [],
expectedSafeSymbols:
[
"Program",
"Program.<Main>$",
"Program.<>c",
"Program.<>c.<<Main>$>b__0_0",
"D",
"D..ctor",
"D.Invoke",
"D.BeginInvoke",
"D.EndInvoke",
]);
}
[Fact]
public void Member_Property()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public int P1 { get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P2 { get; set; }
}
""",
caller: """
var c = new C();
c.P1 = c.P1 + 123;
c.P2 = c.P2 + 123;
unsafe { c.P2 = c.P2 + 123; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.P2", "C.get_P2", "C.set_P2"],
expectedSafeSymbols: ["C.P1", "C.get_P1", "C.set_P1"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'C.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.set").WithLocation(3, 1),
// (3,8): error CS9362: 'C.P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.get").WithLocation(3, 8)
]);
}
[Fact]
public void Member_Property_CompoundAssignment()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P { get; set; }
}
""",
caller: """
var c = new C();
c.P += 123;
unsafe { c.P += 123; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.P", "C.get_P", "C.set_P"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.P.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P += 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P").WithArguments("C.P.set").WithLocation(2, 1),
// (2,1): error CS9362: 'C.P.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P += 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P").WithArguments("C.P.get").WithLocation(2, 1),
]);
}
[Fact]
public void Member_Property_ObjectInitializer()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public C P1 { get; set; }
public C P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
public C P3 { get; [System.Runtime.CompilerServices.RequiresUnsafe] set; }
public C P4 { get; set; }
}
""",
caller: """
_ = new C
{
P1 = null,
P2 = null,
P3 = null,
P4 = null,
};
_ = new C
{
P1 = { },
P2 = { },
P3 = { },
P4 = { },
};
unsafe { _ = new C { P1 = null, P2 = null, P3 = null, P4 = null }; }
unsafe { _ = new C { P1 = { }, P2 = { }, P3 = { }, P4 = { } }; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.P1", "C.get_P1", "C.set_P1", "C.get_P2", "C.set_P3"],
expectedSafeSymbols: ["C", "C.P2", "C.set_P2", "C.P3", "C.get_P3", "C.P4", "C.get_P4", "C.set_P4"],
expectedDiagnostics:
[
// (3,5): error CS9362: 'C.P1.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// P1 = null,
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P1").WithArguments("C.P1.set").WithLocation(3, 5),
// (5,5): error CS9362: 'C.P3.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// P3 = null,
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P3").WithArguments("C.P3.set").WithLocation(5, 5),
// (10,5): error CS9362: 'C.P1.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// P1 = { },
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P1").WithArguments("C.P1.get").WithLocation(10, 5),
// (11,5): error CS9362: 'C.P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// P2 = { },
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P2").WithArguments("C.P2.get").WithLocation(11, 5),
]);
}
[Fact]
public void Member_Property_Pattern()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public int this[int i] => 0;
[System.Runtime.CompilerServices.RequiresUnsafe]
public int Length => 0;
}
""",
caller: """
var c = new C();
_ = c is { Length: 0 };
_ = c is [];
unsafe { _ = c is { Length: 0 }; }
unsafe { _ = c is []; }
""",
additionalSources: [TestSources.Index, RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.this[]", "C.get_Item", "C.Length", "C.get_Length"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (2,12): error CS9362: 'C.Length.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = c is { Length: 0 };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "Length:").WithArguments("C.Length.get").WithLocation(2, 12),
// (3,10): error CS9362: 'C.Length.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = c is [];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[]").WithArguments("C.Length.get").WithLocation(3, 10),
// (3,10): error CS9362: 'C.Length.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = c is [];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[]").WithArguments("C.Length.get").WithLocation(3, 10),
// (3,10): error CS9362: 'C.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = c is [];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[]").WithArguments("C.this[int].get").WithLocation(3, 10),
]);
}
[Fact]
public void Member_Property_Extension()
{
CompileAndVerifyUnsafe(
lib: """
public static class E
{
extension(int x)
{
public int P1 { get => x; set { } }
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P2 { get => x; set { } }
}
}
""",
caller: """
var x = 111;
x.P1 = x.P1 + 222;
x.P2 = x.P2 + 333;
E.get_P1(x); E.set_P1(x, 0);
E.get_P2(x); E.set_P2(x, 0);
unsafe { x.P2 = x.P2 + 444; }
unsafe { E.get_P2(x); E.set_P2(x, 0); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: [ExtensionMember("E", "P2"), "E.get_P2", ExtensionMember("E", "get_P2"), "E.set_P2", ExtensionMember("E", "set_P2")],
expectedSafeSymbols: [ExtensionMember("E", "P1"), "E.get_P1", ExtensionMember("E", "get_P1"), "E.set_P1", ExtensionMember("E", "set_P1")],
expectedNoAttributeInSource: ["E.get_P2", "E.set_P2"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'E.extension(int).P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// x.P2 = x.P2 + 333;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "x.P2").WithArguments("E.extension(int).P2.set").WithLocation(3, 1),
// (3,8): error CS9362: 'E.extension(int).P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// x.P2 = x.P2 + 333;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "x.P2").WithArguments("E.extension(int).P2.get").WithLocation(3, 8),
// (5,1): error CS9362: 'E.get_P2(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E.get_P2(x); E.set_P2(x, 0);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E.get_P2(x)").WithArguments("E.get_P2(int)").WithLocation(5, 1),
// (5,14): error CS9362: 'E.set_P2(int, int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E.get_P2(x); E.set_P2(x, 0);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E.set_P2(x, 0)").WithArguments("E.set_P2(int, int)").WithLocation(5, 14),
]);
}
[Fact]
public void Member_Property_Record()
{
CompileAndVerifyUnsafe(
lib: """
public record C(int P1, int P2)
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P2 { get; set; } = P2;
}
""",
caller: """
var c = new C(1, 2);
c.P2 = c.P1 + c.P2;
unsafe { c.P2 = c.P1 + c.P2; }
""",
additionalSources: [IsExternalInitTypeDefinition, RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.P2", "C.get_P2", "C.set_P2"],
expectedSafeSymbols: ["C.P1", "C.get_P1", "C.set_P1"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P1 + c.P2;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.set").WithLocation(2, 1),
// (2,15): error CS9362: 'C.P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P1 + c.P2;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.get").WithLocation(2, 15),
]);
}
[Fact]
public void Member_Property_Accessors()
{
var lib = """
public class C
{
public int P1 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
public int P2 { get; [System.Runtime.CompilerServices.RequiresUnsafe] set; }
}
""";
CompileAndVerifyUnsafe(
lib: lib,
caller: """
var c = new C();
c.P1 = c.P1 + 123;
c.P2 = c.P2 + 123;
unsafe { c.P1 = c.P1 + 123; }
unsafe { c.P2 = c.P2 + 123; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.get_P1", "C.set_P2"],
expectedSafeSymbols: ["C.P1", "C.P2", "C.get_P2", "C.set_P1"],
expectedDiagnostics:
[
// (2,8): error CS9362: 'C.P1.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P1 = c.P1 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P1").WithArguments("C.P1.get").WithLocation(2, 8),
// (3,1): error CS9362: 'C.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.set").WithLocation(3, 1),
]);
var expectedDiagnostics = new[]
{
// (3,22): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// public int P1 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(3, 22),
// (4,27): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// public int P2 { get; [System.Runtime.CompilerServices.RequiresUnsafe] set; }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(4, 27),
};
CreateCompilation([lib, RequiresUnsafeAttributeDefinition], parseOptions: TestOptions.Regular14).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation([lib, RequiresUnsafeAttributeDefinition], parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation([lib, RequiresUnsafeAttributeDefinition], parseOptions: TestOptions.RegularPreview).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void Member_Property_Attribute()
{
CompileAndVerifyUnsafe(
lib: """
public class A : System.Attribute
{
public int P1 { get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P2 { get; set; }
public int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
public int P4 { get; [System.Runtime.CompilerServices.RequiresUnsafe] set; }
public unsafe int F;
}
""",
caller: """
var c = new C1();
[A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] class C1;
[A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] unsafe class C2;
partial class C3
{
[A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M1() { }
}
unsafe partial class C3
{
[A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M2() { }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["A.P2", "A.get_P2", "A.set_P2", "A.get_P3", "A.set_P4"],
expectedSafeSymbols: ["A.P1", "A.get_P1", "A.set_P1", "A.set_P3", "A.get_P4", "A.F"],
expectedDiagnostics:
[
// (2,12): error CS9362: 'A.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] class C1;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P2 = 0").WithArguments("A.P2.set").WithLocation(2, 12),
// (2,28): error CS9362: 'A.P4.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] class C1;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P4 = 0").WithArguments("A.P4.set").WithLocation(2, 28),
// (6,16): error CS9362: 'A.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M1() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P2 = 0").WithArguments("A.P2.set").WithLocation(6, 16),
// (6,32): error CS9362: 'A.P4.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M1() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P4 = 0").WithArguments("A.P4.set").WithLocation(6, 32),
]);
}
[Fact]
public void Member_Property_Override()
{
CompileAndVerifyUnsafe(
lib: """
public class B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual int P1 { get; set; }
public virtual int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
public virtual int P3 { get; set; }
}
""",
caller: """
var c = new C1();
c.P1 = c.P1 + 123;
c.P2 = c.P2 + 123;
c.P3 = c.P3 + 123;
class C1 : B
{
public override int P1 { get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override int P2 { get; set; }
public override int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
}
class C2 : B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override int P1 { get; set; }
public override int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override int P3 { get; set; }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B.P1", "B.get_P1", "B.set_P1", "B.get_P2"],
expectedSafeSymbols: ["B.P2", "B.set_P2", "B.P3", "B.get_P3", "B.set_P3"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'C1.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C1.P2.set").WithLocation(3, 1),
// (3,8): error CS9362: 'C1.P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C1.P2.get").WithLocation(3, 8),
// (4,8): error CS9362: 'C1.P3.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P3 = c.P3 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P3").WithArguments("C1.P3.get").WithLocation(4, 8),
// (10,35): error CS9364: Unsafe member 'C1.P2.set' cannot override safe member 'B.P2.set'
// public override int P2 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "set").WithArguments("C1.P2.set", "B.P2.set").WithLocation(10, 35),
// (11,79): error CS9364: Unsafe member 'C1.P3.get' cannot override safe member 'B.P3.get'
// public override int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C1.P3.get", "B.P3.get").WithLocation(11, 79),
// (20,30): error CS9364: Unsafe member 'C2.P3.get' cannot override safe member 'B.P3.get'
// public override int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C2.P3.get", "B.P3.get").WithLocation(20, 30),
// (20,35): error CS9364: Unsafe member 'C2.P3.set' cannot override safe member 'B.P3.set'
// public override int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "set").WithArguments("C2.P3.set", "B.P3.set").WithLocation(20, 35),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (3,1): error CS9362: 'C1.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C1.P2.set").WithLocation(3, 1),
// (3,8): error CS9362: 'C1.P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = c.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C1.P2.get").WithLocation(3, 8),
// (4,8): error CS9362: 'C1.P3.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P3 = c.P3 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P3").WithArguments("C1.P3.get").WithLocation(4, 8),
// (10,30): error CS9364: Unsafe member 'C1.P2.get' cannot override safe member 'B.P2.get'
// public override int P2 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C1.P2.get", "B.P2.get").WithLocation(10, 30),
// (10,35): error CS9364: Unsafe member 'C1.P2.set' cannot override safe member 'B.P2.set'
// public override int P2 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "set").WithArguments("C1.P2.set", "B.P2.set").WithLocation(10, 35),
// (11,79): error CS9364: Unsafe member 'C1.P3.get' cannot override safe member 'B.P3.get'
// public override int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C1.P3.get", "B.P3.get").WithLocation(11, 79),
// (17,30): error CS9364: Unsafe member 'C2.P1.get' cannot override safe member 'B.P1.get'
// public override int P1 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C2.P1.get", "B.P1.get").WithLocation(17, 30),
// (17,35): error CS9364: Unsafe member 'C2.P1.set' cannot override safe member 'B.P1.set'
// public override int P1 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "set").WithArguments("C2.P1.set", "B.P1.set").WithLocation(17, 35),
// (18,79): error CS9364: Unsafe member 'C2.P2.get' cannot override safe member 'B.P2.get'
// public override int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C2.P2.get", "B.P2.get").WithLocation(18, 79),
// (20,30): error CS9364: Unsafe member 'C2.P3.get' cannot override safe member 'B.P3.get'
// public override int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "get").WithArguments("C2.P3.get", "B.P3.get").WithLocation(20, 30),
// (20,35): error CS9364: Unsafe member 'C2.P3.set' cannot override safe member 'B.P3.set'
// public override int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "set").WithArguments("C2.P3.set", "B.P3.set").WithLocation(20, 35),
]);
}
[Fact]
public void Member_Property_Implementation()
{
CompileAndVerifyUnsafe(
lib: """
public interface I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
int P1 { get; set; }
int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
int P3 { get; set; }
}
""",
caller: """
I i = new C1();
i.P1 = i.P1 + 123;
i.P2 = i.P2 + 123;
i.P3 = i.P3 + 123;
class C1 : I
{
public int P1 { get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P2 { get; set; }
public int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
}
class C2 : I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P1 { get; set; }
public int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
[System.Runtime.CompilerServices.RequiresUnsafe]
public int P3 { get; set; }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["I.P1", "I.get_P1", "I.set_P1", "I.get_P2"],
expectedSafeSymbols: ["I.P2", "I.set_P2", "I.P3", "I.get_P3", "I.set_P3"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'I.P1.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.P1 = i.P1 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i.P1").WithArguments("I.P1.set").WithLocation(2, 1),
// (2,8): error CS9362: 'I.P1.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.P1 = i.P1 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i.P1").WithArguments("I.P1.get").WithLocation(2, 8),
// (3,8): error CS9362: 'I.P2.get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.P2 = i.P2 + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i.P2").WithArguments("I.P2.get").WithLocation(3, 8),
// (10,26): error CS9365: Unsafe member 'C1.P2.set' cannot implicitly implement safe member 'I.P2.set'
// public int P2 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "set").WithArguments("C1.P2.set", "I.P2.set").WithLocation(10, 26),
// (11,70): error CS9365: Unsafe member 'C1.P3.get' cannot implicitly implement safe member 'I.P3.get'
// public int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C1.P3.get", "I.P3.get").WithLocation(11, 70),
// (20,21): error CS9365: Unsafe member 'C2.P3.get' cannot implicitly implement safe member 'I.P3.get'
// public int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C2.P3.get", "I.P3.get").WithLocation(20, 21),
// (20,26): error CS9365: Unsafe member 'C2.P3.set' cannot implicitly implement safe member 'I.P3.set'
// public int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "set").WithArguments("C2.P3.set", "I.P3.set").WithLocation(20, 26),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (10,21): error CS9365: Unsafe member 'C1.P2.get' cannot implicitly implement safe member 'I.P2.get'
// public int P2 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C1.P2.get", "I.P2.get").WithLocation(10, 21),
// (10,26): error CS9365: Unsafe member 'C1.P2.set' cannot implicitly implement safe member 'I.P2.set'
// public int P2 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "set").WithArguments("C1.P2.set", "I.P2.set").WithLocation(10, 26),
// (11,70): error CS9365: Unsafe member 'C1.P3.get' cannot implicitly implement safe member 'I.P3.get'
// public int P3 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C1.P3.get", "I.P3.get").WithLocation(11, 70),
// (17,21): error CS9365: Unsafe member 'C2.P1.get' cannot implicitly implement safe member 'I.P1.get'
// public int P1 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C2.P1.get", "I.P1.get").WithLocation(17, 21),
// (17,26): error CS9365: Unsafe member 'C2.P1.set' cannot implicitly implement safe member 'I.P1.set'
// public int P1 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "set").WithArguments("C2.P1.set", "I.P1.set").WithLocation(17, 26),
// (18,70): error CS9365: Unsafe member 'C2.P2.get' cannot implicitly implement safe member 'I.P2.get'
// public int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C2.P2.get", "I.P2.get").WithLocation(18, 70),
// (20,21): error CS9365: Unsafe member 'C2.P3.get' cannot implicitly implement safe member 'I.P3.get'
// public int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "get").WithArguments("C2.P3.get", "I.P3.get").WithLocation(20, 21),
// (20,26): error CS9365: Unsafe member 'C2.P3.set' cannot implicitly implement safe member 'I.P3.set'
// public int P3 { get; set; }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "set").WithArguments("C2.P3.set", "I.P3.set").WithLocation(20, 26),
]);
}
[Fact]
public void Member_Indexer()
{
CompileAndVerifyUnsafe(
lib: """
public class C1
{
public int this[int i] { get => i; set { } }
}
public class C2
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public int this[int i] { get => i; set { } }
}
""",
caller: """
var c1 = new C1();
c1[0] = c1[0] + 123;
var c2 = new C2();
c2[0] = c2[0] + 123;
unsafe { c2[0] = c2[0] + 123; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C2.this[]", "C2.get_Item", "C2.set_Item"],
expectedSafeSymbols: ["C1.this[]", "C1.get_Item", "C1.set_Item"],
expectedDiagnostics:
[
// (4,1): error CS9362: 'C2.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c2[0] = c2[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c2[0]").WithArguments("C2.this[int].set").WithLocation(4, 1),
// (4,9): error CS9362: 'C2.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c2[0] = c2[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c2[0]").WithArguments("C2.this[int].get").WithLocation(4, 9),
]);
}
[Fact]
public void Member_Indexer_CompoundAssignment()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public int this[int i] { get => i; set { } }
}
""",
caller: """
var c = new C();
c[0] += 123;
unsafe { c[0] += 123; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.this[]", "C.get_Item", "C.set_Item"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c[0] += 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c[0]").WithArguments("C.this[int].set").WithLocation(2, 1),
// (2,1): error CS9362: 'C.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c[0] += 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c[0]").WithArguments("C.this[int].get").WithLocation(2, 1),
]);
}
[Fact]
public void Member_Indexer_ObjectInitializer()
{
CompileAndVerifyUnsafe(
lib: """
public class C1 { [System.Runtime.CompilerServices.RequiresUnsafe] public object this[int i] { get => null; set { } } }
public class C2 { public object this[int i] { [System.Runtime.CompilerServices.RequiresUnsafe] get => null; set { } } }
public class C3 { public object this[int i] { get => null; [System.Runtime.CompilerServices.RequiresUnsafe] set { } } }
public class C4 { public object this[int i] { get => null; set { } } }
""",
caller: """
_ = new C1 { [0] = null, [0] = { } };
_ = new C2 { [0] = null, [0] = { } };
_ = new C3 { [0] = null, [0] = { } };
_ = new C4 { [0] = null, [0] = { } };
unsafe { _ = new C1 { [0] = null, [0] = { } }; }
unsafe { _ = new C2 { [0] = null, [0] = { } }; }
unsafe { _ = new C3 { [0] = null, [0] = { } }; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C1.this[]", "C1.get_Item", "C1.set_Item", "C2.get_Item", "C3.set_Item"],
expectedSafeSymbols: ["C1", "C2", "C2.this[]", "C2.set_Item", "C3", "C3.this[]", "C3.get_Item", "C4", "C4.this[]", "C4.get_Item", "C4.set_Item"],
expectedDiagnostics:
[
// (1,14): error CS9362: 'C1.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C1 { [0] = null, [0] = { } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[0]").WithArguments("C1.this[int].set").WithLocation(1, 14),
// (1,26): error CS9362: 'C1.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C1 { [0] = null, [0] = { } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[0]").WithArguments("C1.this[int].get").WithLocation(1, 26),
// (2,26): error CS9362: 'C2.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C2 { [0] = null, [0] = { } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[0]").WithArguments("C2.this[int].get").WithLocation(2, 26),
// (3,14): error CS9362: 'C3.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C3 { [0] = null, [0] = { } };
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "[0]").WithArguments("C3.this[int].set").WithLocation(3, 14),
]);
}
[Fact]
public void Member_Indexer_Accessors()
{
var lib = """
public class C1
{
public int this[int i] { [System.Runtime.CompilerServices.RequiresUnsafe] get => i; set { } }
}
public class C2
{
public int this[int i] { get => i; [System.Runtime.CompilerServices.RequiresUnsafe] set { } }
}
""";
CompileAndVerifyUnsafe(
lib: lib,
caller: """
var c1 = new C1();
c1[0] = c1[0] + 123;
var c2 = new C2();
c2[0] = c2[0] + 123;
unsafe { c1[0] = c1[0] + 123; }
unsafe { c2[0] = c2[0] + 123; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C1.get_Item", "C2.set_Item"],
expectedSafeSymbols: ["C1.this[]", "C2.this[]", "C2.get_Item", "C1.set_Item"],
expectedDiagnostics:
[
// (2,9): error CS9362: 'C1.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c1[0] = c1[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c1[0]").WithArguments("C1.this[int].get").WithLocation(2, 9),
// (4,1): error CS9362: 'C2.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c2[0] = c2[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c2[0]").WithArguments("C2.this[int].set").WithLocation(4, 1),
]);
var expectedDiagnostics = new[]
{
// (3,31): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// public int this[int i] { [System.Runtime.CompilerServices.RequiresUnsafe] get => i; set { } }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(3, 31),
// (7,41): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// public int this[int i] { get => i; [System.Runtime.CompilerServices.RequiresUnsafe] set { } }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(7, 41),
};
CreateCompilation([lib, RequiresUnsafeAttributeDefinition], parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation([lib, RequiresUnsafeAttributeDefinition], parseOptions: TestOptions.RegularPreview).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void Member_Event()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public event System.Action E1 { add { } remove { } }
[System.Runtime.CompilerServices.RequiresUnsafe]
public event System.Action E2 { add { } remove { } }
}
""",
caller: """
var c = new C();
c.E1 += null;
c.E2 += null;
unsafe { c.E2 += null; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.E2", "C.add_E2", "C.remove_E2"],
expectedSafeSymbols: ["C.E1", "C.add_E1", "C.remove_E1"],
expectedDiagnostics:
[
// (3,6): error CS9362: 'C.E2.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E2 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C.E2.add").WithLocation(3, 6),
]);
var source = """
class C
{
event System.Action E1, E2;
[System.Runtime.CompilerServices.RequiresUnsafe] event System.Action E3, E4;
void M()
{
E1();
E2();
E3();
E4();
E1 = null;
E2 = null;
E3 = null;
E4 = null;
unsafe { E3(); }
unsafe { E4(); }
unsafe { E3 = null; }
unsafe { E4 = null; }
}
}
""";
CreateCompilation([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (9,9): error CS9362: 'C.E3' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E3();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E3").WithArguments("C.E3").WithLocation(9, 9),
// (10,9): error CS9362: 'C.E4' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E4();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E4").WithArguments("C.E4").WithLocation(10, 9),
// (14,9): error CS9362: 'C.E3' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E3 = null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E3").WithArguments("C.E3").WithLocation(14, 9),
// (15,9): error CS9362: 'C.E4' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E4 = null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E4").WithArguments("C.E4").WithLocation(15, 9));
}
[Fact]
public void Member_Event_Accessors()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public event System.Action E1 { [System.Runtime.CompilerServices.RequiresUnsafe] add { } remove { } }
public event System.Action E2 { add { } [System.Runtime.CompilerServices.RequiresUnsafe] remove { } }
}
""",
caller: """
var c = new C();
c.E1 += null; c.E1 -= null;
c.E2 += null; c.E2 -= null;
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.add_E1", "C.remove_E2"],
expectedSafeSymbols: ["C.E1", "C.remove_E1", "C.E2", "C.add_E2"],
expectedDiagnostics:
[
// (2,6): error CS9362: 'C.E1.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E1 += null; c.E1 -= null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C.E1.add").WithLocation(2, 6),
// (3,20): error CS9362: 'C.E2.remove' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E2 += null; c.E2 -= null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "-=").WithArguments("C.E2.remove").WithLocation(3, 20),
]);
}
[Fact]
public void Member_Event_Override()
{
CompileAndVerifyUnsafe(
lib: """
#pragma warning disable CS0067 // unused event
public class B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual event System.Action E1;
[System.Runtime.CompilerServices.RequiresUnsafe]
public virtual event System.Action E2 { add { } remove { } }
public virtual event System.Action E3;
public virtual event System.Action E4 { add { } remove { } }
}
""",
caller: """
var c = new C1();
c.E1 += null;
c.E2 += null;
c.E3 += null;
c.E4 += null;
#pragma warning disable CS0067 // unused event
class C1 : B
{
public override event System.Action E1;
public override event System.Action E2 { add { } remove { } }
[System.Runtime.CompilerServices.RequiresUnsafe]
public override event System.Action E3;
[System.Runtime.CompilerServices.RequiresUnsafe]
public override event System.Action E4 { add { } remove { } }
}
class C2 : B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public override event System.Action E1;
[System.Runtime.CompilerServices.RequiresUnsafe]
public override event System.Action E2 { add { } remove { } }
public override event System.Action E3;
public override event System.Action E4 { add { } remove { } }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B.E1", "B.add_E1", "B.remove_E1", "B.E2", "B.add_E2", "B.remove_E2"],
expectedSafeSymbols: ["B.E3", "B.add_E3", "B.remove_E3", "B.E4", "B.add_E4", "B.remove_E4"],
expectedDiagnostics:
[
// (4,6): error CS9362: 'C1.E3.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E3 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C1.E3.add").WithLocation(4, 6),
// (5,6): error CS9362: 'C1.E4.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E4 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C1.E4.add").WithLocation(5, 6),
// (14,41): error CS9364: Unsafe member 'C1.E3' cannot override safe member 'B.E3'
// public override event System.Action E3;
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "E3").WithArguments("C1.E3", "B.E3").WithLocation(14, 41),
// (16,41): error CS9364: Unsafe member 'C1.E4' cannot override safe member 'B.E4'
// public override event System.Action E4 { add { } remove { } }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "E4").WithArguments("C1.E4", "B.E4").WithLocation(16, 41),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (4,6): error CS9362: 'C1.E3.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E3 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C1.E3.add").WithLocation(4, 6),
// (5,6): error CS9362: 'C1.E4.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.E4 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C1.E4.add").WithLocation(5, 6),
// (14,41): error CS9364: Unsafe member 'C1.E3' cannot override safe member 'B.E3'
// public override event System.Action E3;
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "E3").WithArguments("C1.E3", "B.E3").WithLocation(14, 41),
// (16,41): error CS9364: Unsafe member 'C1.E4' cannot override safe member 'B.E4'
// public override event System.Action E4 { add { } remove { } }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "E4").WithArguments("C1.E4", "B.E4").WithLocation(16, 41),
// (22,41): error CS9364: Unsafe member 'C2.E1' cannot override safe member 'B.E1'
// public override event System.Action E1;
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "E1").WithArguments("C2.E1", "B.E1").WithLocation(22, 41),
// (24,41): error CS9364: Unsafe member 'C2.E2' cannot override safe member 'B.E2'
// public override event System.Action E2 { add { } remove { } }
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "E2").WithArguments("C2.E2", "B.E2").WithLocation(24, 41),
]);
}
[Fact]
public void Member_Event_Implementation()
{
CompileAndVerifyUnsafe(
lib: """
public interface I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
event System.Action E1;
event System.Action E2;
}
""",
caller: """
I i = new C1();
i.E1 += null;
i.E2 += null;
#pragma warning disable CS0067 // unused event
class C1 : I
{
public event System.Action E1;
[System.Runtime.CompilerServices.RequiresUnsafe]
public event System.Action E2;
}
class C2 : I
{
public event System.Action E1 { add { } remove { } }
[System.Runtime.CompilerServices.RequiresUnsafe]
public event System.Action E2 { add { } remove { } }
}
class C3 : I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public event System.Action E1;
public event System.Action E2;
}
class C4 : I
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public event System.Action E1 { add { } remove { } }
public event System.Action E2 { add { } remove { } }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["I.E1", "I.add_E1", "I.remove_E1"],
expectedSafeSymbols: ["I.E2", "I.add_E2", "I.remove_E2"],
expectedDiagnostics:
[
// (2,6): error CS9362: 'I.E1.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.E1 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("I.E1.add").WithLocation(2, 6),
// (11,32): error CS9365: Unsafe member 'C1.E2' cannot implicitly implement safe member 'I.E2'
// public event System.Action E2;
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "E2").WithArguments("C1.E2", "I.E2").WithLocation(11, 32),
// (18,32): error CS9365: Unsafe member 'C2.E2' cannot implicitly implement safe member 'I.E2'
// public event System.Action E2 { add { } remove { } }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "E2").WithArguments("C2.E2", "I.E2").WithLocation(18, 32),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (11,32): error CS9365: Unsafe member 'C1.E2' cannot implicitly implement safe member 'I.E2'
// public event System.Action E2;
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "E2").WithArguments("C1.E2", "I.E2").WithLocation(11, 32),
// (18,32): error CS9365: Unsafe member 'C2.E2' cannot implicitly implement safe member 'I.E2'
// public event System.Action E2 { add { } remove { } }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "E2").WithArguments("C2.E2", "I.E2").WithLocation(18, 32),
// (24,32): error CS9365: Unsafe member 'C3.E1' cannot implicitly implement safe member 'I.E1'
// public event System.Action E1;
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "E1").WithArguments("C3.E1", "I.E1").WithLocation(24, 32),
// (31,32): error CS9365: Unsafe member 'C4.E1' cannot implicitly implement safe member 'I.E1'
// public event System.Action E1 { add { } remove { } }
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "E1").WithArguments("C4.E1", "I.E1").WithLocation(31, 32),
]);
}
[Fact]
public void Member_Constructor()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public C(int i) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public C() { }
}
public unsafe class C2(int x)
{
int _x = x;
}
[method: System.Runtime.CompilerServices.RequiresUnsafe] public class C3();
""",
caller: """
_ = new C(0);
_ = new C();
unsafe { _ = new C(); }
_ = new C2(0);
_ = new C3();
unsafe { _ = new C3(); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: [Overload("C..ctor", parameterCount: 0)],
expectedSafeSymbols: ["C", Overload("C..ctor", parameterCount: 1), "C2", "C2..ctor"],
expectedDiagnostics:
[
// (2,5): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C()").WithArguments("C.C()").WithLocation(2, 5),
// (5,5): error CS9362: 'C3.C3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C3();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C3()").WithArguments("C3.C3()").WithLocation(5, 5),
]);
}
[Fact]
public void Member_Constructor_Base()
{
CompileAndVerifyUnsafe(
lib: """
public class B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public B() { }
}
""",
caller: """
_ = new C1();
_ = new C2();
_ = new C3();
_ = new C4();
_ = new C5();
_ = new D1();
_ = new D2();
unsafe { _ = new C5(); }
class C1 : B;
class C2 : B
{
public C2() { }
public C2(int x) : base() { }
}
class D1() : B();
unsafe class C3 : B;
unsafe class C4 : B
{
public C4() { }
public C4(int x) : base() { }
}
unsafe class D2() : B();
class C5 : B
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public C5() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public C5(int x) : base() { }
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["B..ctor"],
expectedSafeSymbols: ["B"],
expectedDiagnostics:
[
// (5,5): error CS9362: 'C5.C5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C5();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C5()").WithArguments("C5.C5()").WithLocation(5, 5),
// (10,1): error CS9362: 'B.B()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// class C1 : B;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "class C1 : B;").WithArguments("B.B()").WithLocation(10, 1),
// (13,5): error CS9362: 'B.B()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public C2() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "public C2() { }").WithArguments("B.B()").WithLocation(13, 5),
// (14,22): error CS9362: 'B.B()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public C2(int x) : base() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, ": base()").WithArguments("B.B()").WithLocation(14, 22),
// (16,14): error CS9362: 'B.B()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// class D1() : B();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "B()").WithArguments("B.B()").WithLocation(16, 14),
// (28,5): error CS9362: 'B.B()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [System.Runtime.CompilerServices.RequiresUnsafe]
// public C5() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, @"[System.Runtime.CompilerServices.RequiresUnsafe]
public C5() { }").WithArguments("B.B()").WithLocation(28, 5),
// (31,22): error CS9362: 'B.B()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public C5(int x) : base() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, ": base()").WithArguments("B.B()").WithLocation(31, 22),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (5,5): error CS9362: 'C5.C5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C5();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C5()").WithArguments("C5.C5()").WithLocation(5, 5),
]);
}
[Fact]
public void Member_Constructor_This()
{
var source = """
class C
{
public C() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public C(int x) { }
public C(string s) : this() { }
public C(C c) : this(0) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public C(int[] a) : this(0) { }
}
""";
CreateCompilation([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (7,19): error CS9362: 'C.C(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public C(C c) : this(0) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, ": this(0)").WithArguments("C.C(int)").WithLocation(7, 19),
// (9,23): error CS9362: 'C.C(int)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public C(int[] a) : this(0) { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, ": this(0)").WithArguments("C.C(int)").WithLocation(9, 23));
}
[Fact]
public void Member_Constructor_Static()
{
CreateCompilation(
[
"""
public class C
{
public static readonly int F = 42;
[System.Runtime.CompilerServices.RequiresUnsafe]
static C() { }
}
""",
RequiresUnsafeAttributeDefinition,
],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,6): error CS9367: RequiresUnsafeAttribute cannot be applied to this symbol.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeUnsupportedMemberTarget, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(4, 6));
}
[Fact]
public void Member_Constructor_Attribute()
{
CompileAndVerifyUnsafe(
lib: """
public class A : System.Attribute
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public A() { }
public A(int x) { }
}
""",
caller: """
#pragma warning disable CS8321 // unused local function
[A] void M1() { }
[A(0)] void M2() { }
unsafe { [A] void M3() { } }
[A] unsafe void M4() { }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: [Overload("A..ctor", parameterCount: 0)],
expectedSafeSymbols: ["A", Overload("A..ctor", parameterCount: 1)],
expectedDiagnostics:
[
// (2,2): error CS9362: 'A.A()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// [A] void M1() { }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "A").WithArguments("A.A()").WithLocation(2, 2),
]);
}
[Fact]
public void Member_Destructor()
{
var comp = CreateCompilation(
[
"""
class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
~C() { }
void M() { Finalize(); }
}
class D : C
{
~D() { } // implicitly calls base finalizer
}
""",
RequiresUnsafeAttributeDefinition,
],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,6): error CS9367: RequiresUnsafeAttribute cannot be applied to this symbol.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeUnsupportedMemberTarget, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(3, 6),
// (5,16): error CS0245: Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available.
// void M() { Finalize(); }
Diagnostic(ErrorCode.ERR_CallingFinalizeDeprecated, "Finalize()").WithLocation(5, 16));
VerifyRequiresUnsafeAttribute(
comp.SourceModule,
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C.Finalize"],
expectedAttribute: ["C.Finalize"]);
}
[Fact]
public void Member_Operator_Static()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public static C operator +(C c1, C c2) => c1;
[System.Runtime.CompilerServices.RequiresUnsafe]
public static C operator -(C c1, C c2) => c1;
}
""",
caller: """
var c = new C();
_ = c + c;
_ = c - c;
unsafe { _ = c - c; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.op_Subtraction"],
expectedSafeSymbols: ["C.op_Addition"],
expectedDiagnostics:
[
// (3,5): error CS9362: 'C.operator -(C, C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = c - c;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c - c").WithArguments("C.operator -(C, C)").WithLocation(3, 5),
]);
}
[Fact]
public void Member_Operator_Static_Extension()
{
CompileAndVerifyUnsafe(
lib: """
public class C;
public static class E
{
extension(C)
{
public static C operator +(C c1, C c2) => c1;
[System.Runtime.CompilerServices.RequiresUnsafe]
public static C operator -(C c1, C c2) => c1;
}
}
""",
caller: """
var c = new C();
_ = c + c;
_ = c - c;
E.op_Addition(c, c);
E.op_Subtraction(c, c);
unsafe { _ = c - c; }
unsafe { E.op_Subtraction(c, c); }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["E.op_Subtraction", ExtensionMember("E", "op_Subtraction")],
expectedSafeSymbols: ["E.op_Addition", ExtensionMember("E", "op_Addition")],
expectedDiagnostics:
[
// (3,5): error CS9362: 'E.extension(C).operator -(C, C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = c - c;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c - c").WithArguments("E.extension(C).operator -(C, C)").WithLocation(3, 5),
// (5,1): error CS9362: 'E.op_Subtraction(C, C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E.op_Subtraction(c, c);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E.op_Subtraction(c, c)").WithArguments("E.op_Subtraction(C, C)").WithLocation(5, 1),
]);
}
[Fact]
public void Member_Operator_Instance()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public void operator +=(C c) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void operator -=(C c) { }
}
""",
caller: """
var c = new C();
c += c;
c -= c;
unsafe { c -= c; }
""",
additionalSources: [CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.op_SubtractionAssignment"],
expectedSafeSymbols: ["C.op_AdditionAssignment"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'C.operator -=(C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c -= c;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c -= c").WithArguments("C.operator -=(C)").WithLocation(3, 1),
]);
}
[Fact]
public void Member_Operator_Instance_Extension()
{
CompileAndVerifyUnsafe(
lib: """
public class C;
public static class E
{
extension(C c1)
{
public void operator +=(C c2) { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void operator -=(C c2) { }
}
}
""",
caller: """
var c = new C();
c += c;
c -= c;
E.op_AdditionAssignment(c, c);
E.op_SubtractionAssignment(c, c);
unsafe { c -= c; }
unsafe { E.op_SubtractionAssignment(c, c); }
""",
additionalSources: [CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["E.op_SubtractionAssignment", ExtensionMember("E", "op_SubtractionAssignment")],
expectedSafeSymbols: ["E.op_AdditionAssignment", ExtensionMember("E", "op_AdditionAssignment")],
expectedDiagnostics:
[
// (3,1): error CS9362: 'E.extension(C).operator -=(C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c -= c;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c -= c").WithArguments("E.extension(C).operator -=(C)").WithLocation(3, 1),
// (5,1): error CS9362: 'E.op_SubtractionAssignment(C, C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// E.op_SubtractionAssignment(c, c);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "E.op_SubtractionAssignment(c, c)").WithArguments("E.op_SubtractionAssignment(C, C)").WithLocation(5, 1),
]);
}
[Fact]
public void Member_Operator_Instance_Unary()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public void operator ++() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
public void operator --() { }
}
""",
caller: """
var c = new C();
c++;
c--;
unsafe { c--; }
""",
additionalSources: [CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: ["C.op_DecrementAssignment"],
expectedSafeSymbols: ["C.op_IncrementAssignment"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'C.operator --()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c--;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c--").WithArguments("C.operator --()").WithLocation(3, 1),
]);
}
[Fact]
public void Member_Operator_Conversion()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
public static implicit operator int(C c) => 0;
[System.Runtime.CompilerServices.RequiresUnsafe]
public static implicit operator string(C c) => "";
}
""",
caller: """
var c = new C();
int i = c;
string s = c;
unsafe { string s2 = c; }
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
expectedUnsafeSymbols: [OverloadByReturnType("C.op_Implicit", "System.String")],
expectedSafeSymbols: [OverloadByReturnType("C.op_Implicit", "System.Int32")],
expectedDiagnostics:
[
// (3,12): error CS9362: 'C.implicit operator string(C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// string s = c;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c").WithArguments("C.implicit operator string(C)").WithLocation(3, 12),
]);
}
[Theory, CombinatorialData]
public void Member_FunctionPointer(bool useCompilationReference)
{
var lib = CreateCompilation("""
public unsafe class C
{
public delegate*<string> F;
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
string s = c.F();
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,12): error CS9360: This operation may only be used in an unsafe context
// string s = c.F();
Diagnostic(ErrorCode.ERR_UnsafeOperation, "c.F()").WithLocation(2, 12));
CompileAndVerify("""
var c = new C();
unsafe { string s = c.F(); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C", "C.F", (object)getFunctionPointerType, (object)getFunctionPointerMethod],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (2,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// string s = c.F();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.F()").WithLocation(2, 12));
static Symbol getFunctionPointerType(ModuleSymbol module)
{
return module.GlobalNamespace.GetMember("C.F").GetTypeOrReturnType().Type;
}
static Symbol getFunctionPointerMethod(ModuleSymbol module)
{
var functionPointerType = (FunctionPointerTypeSymbol)getFunctionPointerType(module);
return functionPointerType.Signature;
}
}
[Theory, CombinatorialData]
public void CompatMode_Method_ParameterType(
[CombinatorialValues("int*", "int*[]", "delegate*<void>")] string parameterType,
bool unsafeOnType,
bool useCompilationReference)
{
var (typeModifier, methodModifier) = unsafeOnType ? ("unsafe", "") : ("", "unsafe");
var lib = CreateCompilation($$"""
public {{typeModifier}} class C
{
public {{methodModifier}} void M1(int x) { }
public {{methodModifier}} void M2({{parameterType}} y) { }
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c.M1(0);
c.M2(null);
unsafe { c.M2(null); }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,1): error CS9363: 'C.M2(int*)' must be used in an unsafe context because it has pointers in its signature
// c.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.M2(null)").WithArguments($"C.M2({parameterType})").WithLocation(3, 1));
CompileAndVerify("""
var c = new C();
c.M1(0);
unsafe { c.M2(null); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["C.M2"],
expectedSafeSymbols: ["C", "C.M1"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (3,6): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(3, 6),
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.M2(null)").WithLocation(3, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Method_ReturnType(
[CombinatorialValues("int*", "int*[]", "delegate*<void>")] string returnType,
bool useCompilationReference)
{
var lib = CreateCompilation($$"""
public class C
{
public unsafe int M1(int i) => i;
public unsafe {{returnType}} M2(string s) => null;
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c.M1(0);
c.M2(null);
unsafe { c.M2(null); }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,1): error CS9363: 'C.M2(string)' must be used in an unsafe context because it has pointers in its signature
// c.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.M2(null)").WithArguments("C.M2(string)").WithLocation(3, 1));
CompileAndVerify("""
var c = new C();
c.M1(0);
unsafe { c.M2(null); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["C.M2"],
expectedSafeSymbols: ["C", "C.M1"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.M2(null)").WithLocation(3, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Method_ConstraintType(bool useCompilationReference)
{
var lib = CreateCompilation("""
public class C
{
public unsafe void M<T>(T t) where T : I<int*[]> { }
}
public interface I<T>;
public unsafe class D : I<int*[]>;
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c.M<D>(null);
""";
CompileAndVerify(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
symbolValidator: validate)
.VerifyDiagnostics();
CompileAndVerify(source,
[libRef],
options: TestOptions.UnsafeReleaseExe,
symbolValidator: validate)
.VerifyDiagnostics();
static void validate(ModuleSymbol module)
{
VerifyRequiresUnsafeAttribute(
module.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C", "I", "C.M", "D"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Theory, CombinatorialData]
public void CompatMode_Method_DefaultParameterValue(bool useCompilationReference)
{
var lib = CreateCompilation("""
public class C
{
public unsafe void M(string s = nameof(I<int*[]>)) { }
}
public interface I<T>;
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c.M(s: null);
""";
CompileAndVerify(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
symbolValidator: validate)
.VerifyDiagnostics();
CompileAndVerify(source,
[libRef],
options: TestOptions.UnsafeReleaseExe,
symbolValidator: validate)
.VerifyDiagnostics();
static void validate(ModuleSymbol module)
{
VerifyRequiresUnsafeAttribute(
module.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C", "C.M", "I"]);
}
}
[Theory, CombinatorialData]
public void CompatMode_Method_ExtensionMethod_ReceiverType(bool useCompilationReference)
{
var lib = CreateCompilation("""
public static class E
{
public static unsafe void M1(this int x) { }
public static unsafe void M2(this int*[] y) { }
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
123.M1();
new int*[0].M2();
E.M1(123);
E.M2(null);
unsafe { new int*[0].M2(); }
unsafe { E.M2(null); }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'E.M2(int*[])' must be used in an unsafe context because it has pointers in its signature
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "new int*[0].M2()").WithArguments("E.M2(int*[])").WithLocation(2, 1),
// (4,1): error CS9363: 'E.M2(int*[])' must be used in an unsafe context because it has pointers in its signature
// E.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "E.M2(null)").WithArguments("E.M2(int*[])").WithLocation(4, 1));
CompileAndVerify("""
123.M1();
E.M1(123);
unsafe { new int*[0].M2(); }
unsafe { E.M2(null); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["E.M2"],
expectedSafeSymbols: ["E", "E.M1"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (2,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 5),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new int*[0]").WithLocation(2, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new int*[0].M2()").WithLocation(2, 1),
// (4,6): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(4, 6),
// (4,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "E.M2(null)").WithLocation(4, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Method_ExtensionMember_ReceiverType(bool useCompilationReference)
{
var lib = CreateCompilation("""
public unsafe static class E
{
extension(int x)
{
public void M1() { }
}
extension(int*[] y)
{
public void M2() { }
}
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
123.M1();
new int*[0].M2();
E.M1(123);
E.M2(null);
unsafe { new int*[0].M2(); }
unsafe { E.M2(null); }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'E.extension(int*[]).M2()' must be used in an unsafe context because it has pointers in its signature
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "new int*[0].M2()").WithArguments("E.extension(int*[]).M2()").WithLocation(2, 1),
// (4,1): error CS9363: 'E.M2(int*[])' must be used in an unsafe context because it has pointers in its signature
// E.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "E.M2(null)").WithArguments("E.M2(int*[])").WithLocation(4, 1));
CompileAndVerify("""
123.M1();
E.M1(123);
unsafe { new int*[0].M2(); }
unsafe { E.M2(null); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["E.M2", ExtensionMember("E", "M2")],
expectedSafeSymbols: ["E", "E.M1", ExtensionMember("E", "M1")],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (2,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 5),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new int*[0]").WithLocation(2, 1),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].M2();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new int*[0].M2()").WithLocation(2, 1),
// (4,6): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(4, 6),
// (4,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.M2(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "E.M2(null)").WithLocation(4, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Method_Override(bool useCompilationReference)
{
var lib = CreateCompilation("""
public class B
{
public unsafe virtual int* M1() => null;
public unsafe virtual int* M2() => null;
public unsafe virtual int* M3() => null;
public unsafe virtual void M4() { }
public unsafe virtual void M5() { }
public unsafe virtual void M6() { }
}
public class C : B
{
public unsafe override int* M1() => null;
public unsafe new virtual int* M2() => null;
public unsafe override void M4() { }
public unsafe new virtual void M5() { }
}
""",
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
CreateCompilation("""
var d1 = new D1(); d1.M1(); d1.M2(); d1.M3(); d1.M4(); d1.M5(); d1.M6();
var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
class D1 : C
{
public override int* M1() => null;
public override int* M2() => null;
public override int* M3() => null;
public override void M4() { }
public override void M5() { }
public override void M6() { }
public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
}
class D2 : C
{
public unsafe override int* M1() => null;
public unsafe override int* M2() => null;
public unsafe override int* M3() => null;
public unsafe override void M4() { }
public unsafe override void M5() { }
public unsafe override void M6() { }
}
class D3 : C;
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,20): error CS9363: 'C.M1()' must be used in an unsafe context because it has pointers in its signature
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "d3.M1()").WithArguments("C.M1()").WithLocation(3, 20),
// (3,29): error CS9363: 'C.M2()' must be used in an unsafe context because it has pointers in its signature
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "d3.M2()").WithArguments("C.M2()").WithLocation(3, 29),
// (3,38): error CS9363: 'B.M3()' must be used in an unsafe context because it has pointers in its signature
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "d3.M3()").WithArguments("B.M3()").WithLocation(3, 38),
// (4,11): error CS9363: 'C.M1()' must be used in an unsafe context because it has pointers in its signature
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.M1()").WithArguments("C.M1()").WithLocation(4, 11),
// (4,19): error CS9363: 'C.M2()' must be used in an unsafe context because it has pointers in its signature
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.M2()").WithArguments("C.M2()").WithLocation(4, 19),
// (4,27): error CS9363: 'B.M3()' must be used in an unsafe context because it has pointers in its signature
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.M3()").WithArguments("B.M3()").WithLocation(4, 27),
// (14,31): error CS9363: 'C.M1()' must be used in an unsafe context because it has pointers in its signature
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "base.M1()").WithArguments("C.M1()").WithLocation(14, 31),
// (14,42): error CS9363: 'C.M2()' must be used in an unsafe context because it has pointers in its signature
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "base.M2()").WithArguments("C.M2()").WithLocation(14, 42),
// (14,53): error CS9363: 'B.M3()' must be used in an unsafe context because it has pointers in its signature
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "base.M3()").WithArguments("B.M3()").WithLocation(14, 53));
}
[Theory, CombinatorialData]
public void CompatMode_Method_Implementation(bool useCompilationReference)
{
var lib = CreateCompilation("""
public interface I
{
unsafe int* M1();
unsafe void M2();
}
""",
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
I i = new C1();
i.M1();
i.M2();
public class C1 : I
{
public int* M1() => null;
public void M2() { }
}
public class C2 : I
{
int* I.M1() => null;
void I.M2() { }
}
public class C3 : I
{
public unsafe int* M1() => null;
public unsafe void M2() { }
}
public class C4 : I
{
unsafe int* I.M1() => null;
unsafe void I.M2() { }
}
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'I.M1()' must be used in an unsafe context because it has pointers in its signature
// i.M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "i.M1()").WithArguments("I.M1()").WithLocation(2, 1));
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// i.M1();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "i.M1()").WithLocation(2, 1),
// (7,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public int* M1() => null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(7, 12),
// (13,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int* I.M1() => null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 5));
}
[Theory, CombinatorialData]
public void CompatMode_Method_Implementation_Generic(bool useCompilationReference)
{
var lib = CreateCompilation("""
public interface I<T>
{
T M1();
void M2();
}
""",
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
I<int*[]> i = new C1();
i.M1();
i.M2();
public class C1 : I<int*[]>
{
public int*[] M1() => null;
public void M2() { }
}
public class C2 : I<int*[]>
{
int*[] I<int*[]>.M1() => null;
void I<int*[]>.M2() { }
}
public class C3 : I<int*[]>
{
public unsafe int*[] M1() => null;
public unsafe void M2() { }
}
public class C4 : I<int*[]>
{
unsafe int*[] I<int*[]>.M1() => null;
unsafe void I<int*[]>.M2() { }
}
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (5,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public class C1 : I<int*[]>
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(5, 21),
// (11,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public class C2 : I<int*[]>
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(11, 21),
// (23,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public class C4 : I<int*[]>
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(23, 21),
// (17,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public class C3 : I<int*[]>
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(17, 21),
// (7,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public int*[] M1() => null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(7, 12),
// (13,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int*[] I<int*[]>.M1() => null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 14),
// (14,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// void I<int*[]>.M2() { }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(14, 12),
// (13,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// int*[] I<int*[]>.M1() => null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 5),
// (1,3): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// I<int*[]> i = new C1();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 3),
// (2,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// i.M1();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "i.M1()").WithLocation(2, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Property(
[CombinatorialValues("int*", "int*[]", "delegate*<void>")] string type,
bool useCompilationReference)
{
var lib = CreateCompilation($$"""
public class C
{
public unsafe int P1 { get; set; }
public unsafe {{type}} P2 { get; set; }
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c.P1 = c.P1;
c.P2 = c.P2;
unsafe { c.P2 = c.P2; }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,1): error CS9363: 'C.P2.set' must be used in an unsafe context because it has pointers in its signature
// c.P2 = c.P2;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.P2").WithArguments("C.P2.set").WithLocation(3, 1),
// (3,8): error CS9363: 'C.P2.get' must be used in an unsafe context because it has pointers in its signature
// c.P2 = c.P2;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.P2").WithArguments("C.P2.get").WithLocation(3, 8));
CompileAndVerify("""
var c = new C();
c.P1 = c.P1;
unsafe { c.P2 = c.P2; }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["C.P2", "C.get_P2", "C.set_P2"],
expectedSafeSymbols: ["C", "C.P1", "C.get_P1", "C.set_P1"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.P2 = c.P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.P2").WithLocation(3, 1),
// (3,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.P2 = c.P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.P2").WithLocation(3, 8),
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.P2 = c.P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.P2 = c.P2").WithLocation(3, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Property_Extension_ReceiverType(bool useCompilationReference)
{
var lib = CreateCompilation("""
public unsafe static class E
{
extension(int x)
{
public int P1 { get => 0; set { } }
}
extension(int*[] y)
{
public int P2 { get => 0; set { } }
}
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var x = 123;
x.P1 = x.P1;
new int*[0].P2 = new int*[0].P2;
E.get_P1(x); E.set_P1(x, 0);
E.get_P2(null); E.set_P2(null, 0);
unsafe { new int*[0].P2 = new int*[0].P2; }
unsafe { E.get_P2(null); E.set_P2(null, 0); }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,1): error CS9363: 'E.extension(int*[]).P2.set' must be used in an unsafe context because it has pointers in its signature
// new int*[0].P2 = new int*[0].P2;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "new int*[0].P2").WithArguments("E.extension(int*[]).P2.set").WithLocation(3, 1),
// (3,18): error CS9363: 'E.extension(int*[]).P2.get' must be used in an unsafe context because it has pointers in its signature
// new int*[0].P2 = new int*[0].P2;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "new int*[0].P2").WithArguments("E.extension(int*[]).P2.get").WithLocation(3, 18),
// (5,1): error CS9363: 'E.get_P2(int*[])' must be used in an unsafe context because it has pointers in its signature
// E.get_P2(null); E.set_P2(null, 0);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "E.get_P2(null)").WithArguments("E.get_P2(int*[])").WithLocation(5, 1),
// (5,17): error CS9363: 'E.set_P2(int*[], int)' must be used in an unsafe context because it has pointers in its signature
// E.get_P2(null); E.set_P2(null, 0);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "E.set_P2(null, 0)").WithArguments("E.set_P2(int*[], int)").WithLocation(5, 17));
CompileAndVerify("""
var x = 123;
x.P1 = x.P1;
E.get_P1(x); E.set_P1(x, 0);
unsafe { new int*[0].P2 = new int*[0].P2; }
unsafe { E.get_P2(null); E.set_P2(null, 0); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: [ExtensionMember("E", "P2"), "E.get_P2", ExtensionMember("E", "get_P2"), "E.set_P2", ExtensionMember("E", "set_P2")],
expectedSafeSymbols: ["E", ExtensionMember("E", "P1"), "E.get_P1", ExtensionMember("E", "get_P1"), "E.set_P1", ExtensionMember("E", "set_P1")],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].P2 = new int*[0].P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 5),
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].P2 = new int*[0].P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new int*[0]").WithLocation(3, 1),
// (3,22): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].P2 = new int*[0].P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 22),
// (3,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// new int*[0].P2 = new int*[0].P2;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new int*[0]").WithLocation(3, 18),
// (5,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.get_P2(null); E.set_P2(null, 0);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(5, 10),
// (5,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.get_P2(null); E.set_P2(null, 0);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "E.get_P2(null)").WithLocation(5, 1),
// (5,26): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.get_P2(null); E.set_P2(null, 0);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(5, 26),
// (5,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// E.get_P2(null); E.set_P2(null, 0);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "E.set_P2(null, 0)").WithLocation(5, 17));
}
[Theory, CombinatorialData]
public void CompatMode_Indexer(
[CombinatorialValues("int*", "int*[]", "delegate*<void>")] string type,
bool useCompilationReference)
{
var lib = CreateCompilation($$"""
public class C1
{
public unsafe int this[int i] { get => i; set { } }
}
public class C2
{
public unsafe {{type}} this[int i] { get => null; set { } }
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c1 = new C1();
c1[0] = c1[0];
var c2 = new C2();
c2[0] = c2[0];
unsafe { c2[0] = c2[0]; }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,1): error CS9363: 'C2.this[int].set' must be used in an unsafe context because it has pointers in its signature
// c2[0] = c2[0];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c2[0]").WithArguments("C2.this[int].set").WithLocation(4, 1),
// (4,9): error CS9363: 'C2.this[int].get' must be used in an unsafe context because it has pointers in its signature
// c2[0] = c2[0];
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c2[0]").WithArguments("C2.this[int].get").WithLocation(4, 9));
CompileAndVerify("""
var c1 = new C1();
c1[0] = c1[0];
var c2 = new C2();
unsafe { c2[0] = c2[0]; }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["C2.this[]", "C2.get_Item", "C2.set_Item"],
expectedSafeSymbols: ["C1", "C2", "C1.this[]", "C1.get_Item", "C1.set_Item"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (4,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c2[0] = c2[0];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c2[0]").WithLocation(4, 1),
// (4,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c2[0] = c2[0];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c2[0]").WithLocation(4, 9),
// (4,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c2[0] = c2[0];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c2[0] = c2[0]").WithLocation(4, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Event(bool useCompilationReference)
{
var lib = CreateCompilation("""
#pragma warning disable CS0067 // unused event
public class C
{
public unsafe event System.Action E1;
public unsafe event System.Action<int*[]> E2;
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c.E1 += null;
c.E2 += null;
unsafe { c.E2 += null; }
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,6): error CS9363: 'C.E2.add' must be used in an unsafe context because it has pointers in its signature
// c.E2 += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "+=").WithArguments("C.E2.add").WithLocation(3, 6));
CompileAndVerify("""
var c = new C();
c.E1 += null;
unsafe { c.E2 += null; }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["C.E2", "C.add_E2", "C.remove_E2"],
expectedSafeSymbols: ["C", "C.E1", "C.add_E1", "C.remove_E1"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// c.E2 += null;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.E2").WithLocation(3, 1));
}
[Theory, CombinatorialData]
public void CompatMode_Constructor(bool useCompilationReference)
{
var lib = CreateCompilation("""
public class C
{
public unsafe C() { }
public unsafe C(int* p) { }
}
""",
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
_ = new C();
_ = new C(null);
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,5): error CS9363: 'C.C(int*)' must be used in an unsafe context because it has pointers in its signature
// _ = new C(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "new C(null)").WithArguments("C.C(int*)").WithLocation(2, 5));
CompileAndVerify("""
_ = new C();
unsafe { _ = new C(null); }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: [Overload("C..ctor", parameterCount: 1)],
expectedSafeSymbols: ["C", Overload("C..ctor", parameterCount: 0)],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyDiagnostics(
// (2,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = new C(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "new C(null)").WithLocation(2, 5),
// (2,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = new C(null);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "null").WithLocation(2, 11));
}
[Theory, CombinatorialData]
public void CompatMode_Operator(bool useCompilationReference)
{
var lib = CreateCompilation(
[
"""
public class C
{
public unsafe void operator +=(int i) { }
public unsafe void operator -=(int* p) { }
}
""",
CompilerFeatureRequiredAttribute,
],
options: TestOptions.UnsafeReleaseDll,
assemblyName: "lib")
.VerifyDiagnostics();
var libRef = AsReference(lib, useCompilationReference);
var source = """
var c = new C();
c += 0;
c -= null;
""";
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,1): error CS9363: 'C.operator -=(int*)' must be used in an unsafe context because it has pointers in its signature
// c -= null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c -= null").WithArguments("C.operator -=(int*)").WithLocation(3, 1));
CompileAndVerify("""
var c = new C();
c += 0;
unsafe { c -= null; }
""",
[libRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(),
expectedUnsafeSymbols: ["C.op_SubtractionAssignment"],
expectedSafeSymbols: ["C", "C.op_AdditionAssignment"],
expectedUnsafeMode: CallerUnsafeMode.Implicit))
.VerifyDiagnostics();
// https://github.com/dotnet/roslyn/issues/81967: operator invocations involving pointers are allowed outside unsafe context
CreateCompilation(source,
[libRef],
options: TestOptions.UnsafeReleaseExe)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Method()
{
var libSource = """
#pragma warning disable CS0626 // extern without attributes
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class C
{
public void M1() { }
public extern void M2();
[DllImport("test")] public static extern void M3();
[MethodImpl(MethodImplOptions.InternalCall)] public extern void M4();
}
""";
var callerSource = """
var c = new C();
c.M1();
c.M2();
C.M3();
c.M4();
""";
object[] unsafeSymbols = ["C.M2", "C.M3", "C.M4"];
var commonDiagnostics = new[]
{
// (3,1): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M2();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M2()").WithArguments("C.M2()").WithLocation(3, 1),
// (4,1): error CS9362: 'C.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.M3();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M3()").WithArguments("C.M3()").WithLocation(4, 1),
// (5,1): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M4();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M4()").WithArguments("C.M4()").WithLocation(5, 1),
};
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C", "C.M1"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics: commonDiagnostics);
CreateCompilation([libSource, callerSource],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
[
.. commonDiagnostics,
// (8,24): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern void M2();
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "M2").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(8, 24),
// (9,51): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// [DllImport("test")] public static extern void M3();
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "M3").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(9, 51),
// (10,69): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// [MethodImpl(MethodImplOptions.InternalCall)] public extern void M4();
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "M4").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(10, 69),
]);
CreateCompilation([libSource, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (8,24): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern void M2();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "M2").WithArguments("updated memory safety rules").WithLocation(8, 24),
// (9,51): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [DllImport("test")] public static extern void M3();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "M3").WithArguments("updated memory safety rules").WithLocation(9, 51),
// (10,69): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// [MethodImpl(MethodImplOptions.InternalCall)] public extern void M4();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "M4").WithArguments("updated memory safety rules").WithLocation(10, 69));
CreateCompilation(libSource,
parseOptions: TestOptions.Regular14)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Method_WithPointers()
{
static string getLibSource(string modifiers) => $$"""
#pragma warning disable CS0626 // extern without attributes
public class C
{
public {{modifiers}} int* M();
}
""";
var callerSource = """
var c = new C();
c.M();
""";
var libUpdated = CreateCompilation(
[getLibSource("extern"), RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libUpdatedRef = AsReference(libUpdated, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libUpdatedRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M()").WithArguments("C.M()").WithLocation(2, 1))
.GetReferencedAssemblySymbol(libUpdatedRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: ["C.M"]);
}
CreateCompilation(getLibSource("extern")).VerifyDiagnostics(
// (4,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public extern int* M();
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 19));
// When compiling the lib under legacy rules, extern members are not unsafe, but members with pointers are.
var libLegacy = CreateCompilation(
getLibSource("unsafe extern"),
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libLegacyRef = AsReference(libLegacy, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libLegacyRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'C.M()' must be used in an unsafe context because it has pointers in its signature
// c.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.M()").WithArguments("C.M()").WithLocation(2, 1))
.GetReferencedAssemblySymbol(libLegacyRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Fact]
public void Extern_Method_Explicit()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public extern void M();
}
""",
caller: """
var c = new C();
c.M();
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M()").WithArguments("C.M()").WithLocation(2, 1),
]);
}
[Fact]
public void Extern_Method_Override()
{
object[] unsafeSymbols = ["B.M1", "B.M2", "B.M3"];
CompileAndVerifyUnsafe(
lib: """
#pragma warning disable CS0626 // extern without attributes
public class B
{
public extern virtual void M1();
public extern virtual void M2();
public extern virtual void M3();
public virtual void M4() { }
public virtual void M5() { }
public virtual void M6() { }
}
""",
caller: """
#pragma warning disable CS0626 // extern without attributes
var d1 = new D1(); d1.M1(); d1.M2(); d1.M3(); d1.M4(); d1.M5(); d1.M6();
var d2 = new D2(); d2.M1(); d2.M2(); d2.M3(); d2.M4(); d2.M5(); d2.M6();
var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
class C : B
{
public extern override void M1();
public extern new virtual void M2();
public extern override void M4();
public extern new virtual void M5();
}
class D1 : C
{
public override void M1() { }
public override void M2() { }
public override void M3() { }
public override void M4() { }
public override void M5() { }
public override void M6() { }
public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
}
class D2 : C
{
public unsafe override void M1() { }
public unsafe override void M2() { }
public unsafe override void M3() { }
public unsafe override void M4() { }
public unsafe override void M5() { }
public unsafe override void M6() { }
}
class D3 : C
{
public extern override void M1();
public extern override void M2();
public extern override void M3();
public extern override void M4();
public extern override void M5();
public extern override void M6();
}
class D4 : C;
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["B", "B.M4", "B.M5", "B.M6"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics:
[
// (4,20): error CS9362: 'D3.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M1()").WithArguments("D3.M1()").WithLocation(4, 20),
// (4,29): error CS9362: 'D3.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M2()").WithArguments("D3.M2()").WithLocation(4, 29),
// (4,38): error CS9362: 'D3.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M3()").WithArguments("D3.M3()").WithLocation(4, 38),
// (4,47): error CS9362: 'D3.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M4()").WithArguments("D3.M4()").WithLocation(4, 47),
// (4,56): error CS9362: 'D3.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M5()").WithArguments("D3.M5()").WithLocation(4, 56),
// (4,65): error CS9362: 'D3.M6()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M6()").WithArguments("D3.M6()").WithLocation(4, 65),
// (5,20): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M1()").WithArguments("C.M1()").WithLocation(5, 20),
// (5,29): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M2()").WithArguments("C.M2()").WithLocation(5, 29),
// (5,38): error CS9362: 'B.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M3()").WithArguments("B.M3()").WithLocation(5, 38),
// (5,47): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M4()").WithArguments("C.M4()").WithLocation(5, 47),
// (5,56): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M5()").WithArguments("C.M5()").WithLocation(5, 56),
// (6,11): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M1()").WithArguments("C.M1()").WithLocation(6, 11),
// (6,19): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M2()").WithArguments("C.M2()").WithLocation(6, 19),
// (6,27): error CS9362: 'B.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M3()").WithArguments("B.M3()").WithLocation(6, 27),
// (6,35): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M4()").WithArguments("C.M4()").WithLocation(6, 35),
// (6,43): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M5()").WithArguments("C.M5()").WithLocation(6, 43),
// (12,33): error CS9364: Unsafe member 'C.M4()' cannot override safe member 'B.M4()'
// public extern override void M4();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M4").WithArguments("C.M4()", "B.M4()").WithLocation(12, 33),
// (24,31): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M1()").WithArguments("C.M1()").WithLocation(24, 31),
// (24,42): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M2()").WithArguments("C.M2()").WithLocation(24, 42),
// (24,53): error CS9362: 'B.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M3()").WithArguments("B.M3()").WithLocation(24, 53),
// (24,64): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M4()").WithArguments("C.M4()").WithLocation(24, 64),
// (24,75): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M5()").WithArguments("C.M5()").WithLocation(24, 75),
// (42,33): error CS9364: Unsafe member 'D3.M4()' cannot override safe member 'B.M4()'
// public extern override void M4();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M4").WithArguments("D3.M4()", "B.M4()").WithLocation(42, 33),
// (44,33): error CS9364: Unsafe member 'D3.M6()' cannot override safe member 'B.M6()'
// public extern override void M6();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M6").WithArguments("D3.M6()", "B.M6()").WithLocation(44, 33),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (4,20): error CS9362: 'D3.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M1()").WithArguments("D3.M1()").WithLocation(4, 20),
// (4,29): error CS9362: 'D3.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M2()").WithArguments("D3.M2()").WithLocation(4, 29),
// (4,38): error CS9362: 'D3.M3()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M3()").WithArguments("D3.M3()").WithLocation(4, 38),
// (4,47): error CS9362: 'D3.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M4()").WithArguments("D3.M4()").WithLocation(4, 47),
// (4,56): error CS9362: 'D3.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M5()").WithArguments("D3.M5()").WithLocation(4, 56),
// (4,65): error CS9362: 'D3.M6()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d3 = new D3(); d3.M1(); d3.M2(); d3.M3(); d3.M4(); d3.M5(); d3.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d3.M6()").WithArguments("D3.M6()").WithLocation(4, 65),
// (5,20): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M1()").WithArguments("C.M1()").WithLocation(5, 20),
// (5,29): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M2()").WithArguments("C.M2()").WithLocation(5, 29),
// (5,47): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M4()").WithArguments("C.M4()").WithLocation(5, 47),
// (5,56): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// var d4 = new D4(); d4.M1(); d4.M2(); d4.M3(); d4.M4(); d4.M5(); d4.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "d4.M5()").WithArguments("C.M5()").WithLocation(5, 56),
// (6,11): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M1()").WithArguments("C.M1()").WithLocation(6, 11),
// (6,19): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M2()").WithArguments("C.M2()").WithLocation(6, 19),
// (6,35): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M4()").WithArguments("C.M4()").WithLocation(6, 35),
// (6,43): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C c = d1; c.M1(); c.M2(); c.M3(); c.M4(); c.M5(); c.M6();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.M5()").WithArguments("C.M5()").WithLocation(6, 43),
// (10,33): error CS9364: Unsafe member 'C.M1()' cannot override safe member 'B.M1()'
// public extern override void M1();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("C.M1()", "B.M1()").WithLocation(10, 33),
// (12,33): error CS9364: Unsafe member 'C.M4()' cannot override safe member 'B.M4()'
// public extern override void M4();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M4").WithArguments("C.M4()", "B.M4()").WithLocation(12, 33),
// (24,31): error CS9362: 'C.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M1()").WithArguments("C.M1()").WithLocation(24, 31),
// (24,42): error CS9362: 'C.M2()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M2()").WithArguments("C.M2()").WithLocation(24, 42),
// (24,64): error CS9362: 'C.M4()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M4()").WithArguments("C.M4()").WithLocation(24, 64),
// (24,75): error CS9362: 'C.M5()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// public void BaseCalls() { base.M1(); base.M2(); base.M3(); base.M4(); base.M5(); base.M6(); }
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "base.M5()").WithArguments("C.M5()").WithLocation(24, 75),
// (39,33): error CS9364: Unsafe member 'D3.M1()' cannot override safe member 'B.M1()'
// public extern override void M1();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M1").WithArguments("D3.M1()", "B.M1()").WithLocation(39, 33),
// (41,33): error CS9364: Unsafe member 'D3.M3()' cannot override safe member 'B.M3()'
// public extern override void M3();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M3").WithArguments("D3.M3()", "B.M3()").WithLocation(41, 33),
// (42,33): error CS9364: Unsafe member 'D3.M4()' cannot override safe member 'B.M4()'
// public extern override void M4();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M4").WithArguments("D3.M4()", "B.M4()").WithLocation(42, 33),
// (44,33): error CS9364: Unsafe member 'D3.M6()' cannot override safe member 'B.M6()'
// public extern override void M6();
Diagnostic(ErrorCode.ERR_CallerUnsafeOverridingSafe, "M6").WithArguments("D3.M6()", "B.M6()").WithLocation(44, 33),
]);
}
[Fact]
public void Extern_Method_Implementation()
{
CompileAndVerifyUnsafe(
lib: """
#pragma warning disable CS0626 // extern without attributes
public interface I
{
extern void M1();
void M2();
}
""",
caller: """
#pragma warning disable CS0626 // extern without attributes
I i = new C1();
i.M1();
i.M2();
public class C1 : I
{
public void M1() { }
public void M2() { }
}
public class C2 : I
{
void I.M1() { }
void I.M2() { }
}
public class C3 : I
{
public unsafe void M1() { }
public unsafe void M2() { }
}
public class C4 : I
{
unsafe void I.M1() { }
unsafe void I.M2() { }
}
public class C5 : I
{
public extern void M1();
public extern void M2();
}
public class C6 : I
{
extern void I.M1();
extern void I.M2();
}
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
targetFramework: TargetFramework.Net100,
verify: Verification.Skipped,
expectedUnsafeSymbols: ["I.M1"],
expectedSafeSymbols: ["I", "I.M2"],
expectedNoAttributeInSource: ["I.M1"],
expectedNoAttributeUnderLegacyRules: ["I.M1"],
expectedDiagnostics:
[
// (3,1): error CS9362: 'I.M1()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// i.M1();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "i.M1()").WithArguments("I.M1()").WithLocation(3, 1),
// (33,24): error CS9365: Unsafe member 'C5.M2()' cannot implicitly implement safe member 'I.M2()'
// public extern void M2();
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C5.M2()", "I.M2()").WithLocation(33, 24),
// (39,19): error CS9366: Unsafe member 'C6.I.M2()' cannot implement safe member 'I.M2()'
// extern void I.M2();
Diagnostic(ErrorCode.ERR_CallerUnsafeExplicitlyImplementingSafe, "M2").WithArguments("C6.I.M2()", "I.M2()").WithLocation(39, 19),
],
expectedDiagnosticsWhenReferencingLegacyLib:
[
// (32,24): error CS9365: Unsafe member 'C5.M1()' cannot implicitly implement safe member 'I.M1()'
// public extern void M1();
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M1").WithArguments("C5.M1()", "I.M1()").WithLocation(32, 24),
// (33,24): error CS9365: Unsafe member 'C5.M2()' cannot implicitly implement safe member 'I.M2()'
// public extern void M2();
Diagnostic(ErrorCode.ERR_CallerUnsafeImplicitlyImplementingSafe, "M2").WithArguments("C5.M2()", "I.M2()").WithLocation(33, 24),
// (38,19): error CS9366: Unsafe member 'C6.I.M1()' cannot implement safe member 'I.M1()'
// extern void I.M1();
Diagnostic(ErrorCode.ERR_CallerUnsafeExplicitlyImplementingSafe, "M1").WithArguments("C6.I.M1()", "I.M1()").WithLocation(38, 19),
// (39,19): error CS9366: Unsafe member 'C6.I.M2()' cannot implement safe member 'I.M2()'
// extern void I.M2();
Diagnostic(ErrorCode.ERR_CallerUnsafeExplicitlyImplementingSafe, "M2").WithArguments("C6.I.M2()", "I.M2()").WithLocation(39, 19),
]);
}
[Fact]
public void Extern_LocalFunction()
{
var libSource = """
#pragma warning disable CS0626 // extern without attributes
#pragma warning disable CS8321 // unused local function
public class C
{
public void M()
{
static extern void F();
}
}
""";
var callerSource = """
new C().M();
""";
object[] unsafeSymbols = ["C.<M>g__F|0_0"];
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [RequiresUnsafeAttributeDefinition],
optionsDll: TestOptions.UnsafeReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
skipSymbolsInSource: unsafeSymbols,
expectedDiagnostics: []);
CreateCompilation([libSource, callerSource],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (7,28): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// static extern void F();
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "F").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(7, 28));
CreateCompilation([libSource, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (7,28): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// static extern void F();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "F").WithArguments("updated memory safety rules").WithLocation(7, 28));
CreateCompilation(libSource,
parseOptions: TestOptions.Regular14)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Property()
{
var libSource = """
#pragma warning disable CS0626 // extern without attributes
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class C
{
public int P1 { set { } }
public extern int P2 { set; }
public static extern int P3 { [DllImport("test")] set; }
public extern int P4 { [MethodImpl(MethodImplOptions.InternalCall)] set; }
}
""";
var callerSource = """
var c = new C();
c.P1 = 0;
c.P2 = 0;
C.P3 = 0;
c.P4 = 0;
""";
object[] unsafeSymbols = ["C.P2", "C.set_P2", "C.P3", "C.set_P3", "C.P4", "C.set_P4"];
var commonDiagnostics = new[]
{
// (3,1): error CS9362: 'C.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.set").WithLocation(3, 1),
// (4,1): error CS9362: 'C.P3.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.P3 = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.P3").WithArguments("C.P3.set").WithLocation(4, 1),
// (5,1): error CS9362: 'C.P4.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P4 = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P4").WithArguments("C.P4.set").WithLocation(5, 1),
};
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C", "C.P1", "C.set_P1"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics: commonDiagnostics);
CreateCompilation([libSource, callerSource],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics([
.. commonDiagnostics,
// (8,23): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int P2 { set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "P2").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(8, 23),
// (8,28): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int P2 { set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "set").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(8, 28),
// (9,30): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public static extern int P3 { [DllImport("test")] set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "P3").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(9, 30),
// (9,55): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public static extern int P3 { [DllImport("test")] set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "set").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(9, 55),
// (10,23): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int P4 { [MethodImpl(MethodImplOptions.InternalCall)] set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "P4").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(10, 23),
// (10,73): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int P4 { [MethodImpl(MethodImplOptions.InternalCall)] set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "set").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(10, 73),
]);
CreateCompilation([libSource, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (8,23): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int P2 { set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("updated memory safety rules").WithLocation(8, 23),
// (8,28): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int P2 { set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "set").WithArguments("updated memory safety rules").WithLocation(8, 28),
// (9,30): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public static extern int P3 { [DllImport("test")] set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("updated memory safety rules").WithLocation(9, 30),
// (9,55): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public static extern int P3 { [DllImport("test")] set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "set").WithArguments("updated memory safety rules").WithLocation(9, 55),
// (10,23): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int P4 { [MethodImpl(MethodImplOptions.InternalCall)] set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "P4").WithArguments("updated memory safety rules").WithLocation(10, 23),
// (10,73): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int P4 { [MethodImpl(MethodImplOptions.InternalCall)] set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "set").WithArguments("updated memory safety rules").WithLocation(10, 73));
CreateCompilation(libSource,
parseOptions: TestOptions.Regular14)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Property_WithPointers()
{
static string getLibSource(string modifiers) => $$"""
#pragma warning disable CS0626 // extern without attributes
public class C
{
public {{modifiers}} int* P { set; }
}
""";
var callerSource = """
var c = new C();
c.P = null;
""";
var libUpdated = CreateCompilation(
[getLibSource("extern"), RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libUpdatedRef = AsReference(libUpdated, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libUpdatedRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9362: 'C.P.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P = null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P").WithArguments("C.P.set").WithLocation(2, 1))
.GetReferencedAssemblySymbol(libUpdatedRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.P", "C.set_P"],
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: ["C.P", "C.set_P"]);
}
CreateCompilation(getLibSource("extern")).VerifyDiagnostics(
// (4,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public extern int* P { set; }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 19));
// When compiling the lib under legacy rules, extern members are not unsafe, but members with pointers are.
var libLegacy = CreateCompilation(
getLibSource("unsafe extern"),
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libLegacyRef = AsReference(libLegacy, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libLegacyRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'C.P.set' must be used in an unsafe context because it has pointers in its signature
// c.P = null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.P").WithArguments("C.P.set").WithLocation(2, 1))
.GetReferencedAssemblySymbol(libLegacyRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.P", "C.set_P"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Fact]
public void Extern_Property_Explicit()
{
CompileAndVerifyUnsafe(
lib: """
#pragma warning disable CS0626 // extern without attributes
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public extern int P1 { set; }
public extern int P2 { [System.Runtime.CompilerServices.RequiresUnsafe] set; }
}
""",
caller: """
var c = new C();
c.P1 = 0;
c.P2 = 0;
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.P1", "C.set_P1", "C.P2", "C.set_P2"],
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: ["C.P2"],
expectedNoAttributeUnderLegacyRules: ["C.P2"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.P1.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P1 = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P1").WithArguments("C.P1.set").WithLocation(2, 1),
// (3,1): error CS9362: 'C.P2.set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c.P2 = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.P2").WithArguments("C.P2.set").WithLocation(3, 1),
]);
}
[Fact]
public void Extern_Indexer()
{
var libSource = """
#pragma warning disable CS0626 // extern without attributes
public class C
{
public extern int this[int i] { get; set; }
}
""";
var callerSource = """
var c = new C();
c[0] = c[0] + 123;
""";
object[] unsafeSymbols = ["C.this[]", "C.get_Item", "C.set_Item"];
var commonDiagnostics = new[]
{
// (2,1): error CS9362: 'C.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c[0] = c[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c[0]").WithArguments("C.this[int].set").WithLocation(2, 1),
// (2,8): error CS9362: 'C.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c[0] = c[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c[0]").WithArguments("C.this[int].get").WithLocation(2, 8),
};
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics: commonDiagnostics);
CreateCompilation([libSource, callerSource],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
[
.. commonDiagnostics,
// (4,23): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int this[int i] { get; set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(4, 23),
// (4,37): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int this[int i] { get; set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "get").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(4, 37),
// (4,42): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern int this[int i] { get; set; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "set").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(4, 42),
]);
CreateCompilation([libSource, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,23): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int this[int i] { get; set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("updated memory safety rules").WithLocation(4, 23),
// (4,37): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int this[int i] { get; set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("updated memory safety rules").WithLocation(4, 37),
// (4,42): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern int this[int i] { get; set; }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "set").WithArguments("updated memory safety rules").WithLocation(4, 42));
CreateCompilation(libSource,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Indexer_WithPointers()
{
static string getLibSource(string modifiers) => $$"""
#pragma warning disable CS0626 // extern without attributes
public class C
{
public {{modifiers}} int* this[int i] { get; set; }
}
""";
var callerSource = """
var c = new C();
c[0] = c[0] + 123;
""";
var libUpdated = CreateCompilation(
[getLibSource("extern"), RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libUpdatedRef = AsReference(libUpdated, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libUpdatedRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9362: 'C.this[int].set' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c[0] = c[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c[0]").WithArguments("C.this[int].set").WithLocation(2, 1),
// (2,8): error CS9362: 'C.this[int].get' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c[0] = c[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c[0]").WithArguments("C.this[int].get").WithLocation(2, 8))
.GetReferencedAssemblySymbol(libUpdatedRef);
object[] unsafeSymbols = ["C.this[]", "C.get_Item", "C.set_Item"];
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols);
}
CreateCompilation(getLibSource("extern")).VerifyDiagnostics(
// (4,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public extern int* P { set; }
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 19));
// When compiling the lib under legacy rules, extern members are not unsafe, but members with pointers are.
var libLegacy = CreateCompilation(
getLibSource("unsafe extern"),
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libLegacyRef = AsReference(libLegacy, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libLegacyRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'C.this[int].set' must be used in an unsafe context because it has pointers in its signature
// c[0] = c[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c[0]").WithArguments("C.this[int].set").WithLocation(2, 1),
// (2,8): error CS9363: 'C.this[int].get' must be used in an unsafe context because it has pointers in its signature
// c[0] = c[0] + 123;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c[0]").WithArguments("C.this[int].get").WithLocation(2, 8))
.GetReferencedAssemblySymbol(libLegacyRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.this[]", "C.get_Item", "C.set_Item"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Fact]
public void Extern_Indexer_Explicit()
{
CompileAndVerifyUnsafe(
lib: """
#pragma warning disable CS0626 // extern without attributes
public class C1
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public extern int this[int i] { set; }
}
public class C2
{
public extern int this[int i] { [System.Runtime.CompilerServices.RequiresUnsafe] set; }
}
""",
caller: """
new C1()[0] = 0;
new C2()[0] = 0;
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C1.this[]", "C1.set_Item", "C2.this[]", "C2.set_Item"],
expectedSafeSymbols: ["C1", "C2"],
expectedNoAttributeInSource: ["C2.this[]"],
expectedNoAttributeUnderLegacyRules: ["C2.this[]"],
expectedDiagnostics:
[
// (1,1): error CS9362: 'C1.this[int].set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern'
// new C1()[0] = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C1()[0]").WithArguments("C1.this[int].set").WithLocation(1, 1),
// (2,1): error CS9362: 'C2.this[int].set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern'
// new C2()[0] = 0;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C2()[0]").WithArguments("C2.this[int].set").WithLocation(2, 1),
]);
}
[Fact]
public void Extern_Event()
{
var libSource = """
#pragma warning disable CS0067 // unused event
public class C
{
[method: System.Runtime.InteropServices.DllImport("test")]
public static extern event System.Action E;
}
""";
var callerSource = """
C.E += null;
""";
object[] unsafeSymbols = ["C.E", "C.add_E", "C.remove_E"];
var commonDiagnostics = new[]
{
// (1,5): error CS9362: 'C.E.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.E += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C.E.add").WithLocation(1, 5),
};
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics: commonDiagnostics);
CreateCompilation([libSource, callerSource],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics([
.. commonDiagnostics,
// (5,46): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public static extern event System.Action E;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "E").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(5, 46),
// (5,46): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public static extern event System.Action E;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "E").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(5, 46),
// (5,46): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public static extern event System.Action E;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "E").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(5, 46),
]);
CreateCompilation([libSource, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (5,46): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public static extern event System.Action E;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "E").WithArguments("updated memory safety rules").WithLocation(5, 46),
// (5,46): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public static extern event System.Action E;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "E").WithArguments("updated memory safety rules").WithLocation(5, 46),
// (5,46): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public static extern event System.Action E;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "E").WithArguments("updated memory safety rules").WithLocation(5, 46));
CreateCompilation(libSource,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Event_WithPointers()
{
var libSource = """
#pragma warning disable CS0067 // unused event
public class C
{
[method: System.Runtime.InteropServices.DllImport("test")]
public static extern event System.Action<int*[]> E;
}
""";
var callerSource = """
C.E += null;
""";
var libUpdated = CreateCompilation(
[libSource, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libUpdatedRef = AsReference(libUpdated, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libUpdatedRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,5): error CS9362: 'C.E.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.E += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C.E.add").WithLocation(1, 5))
.GetReferencedAssemblySymbol(libUpdatedRef);
object[] unsafeSymbols = ["C.E", "C.add_E", "C.remove_E"];
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols);
}
// When compiling the lib under legacy rules, extern members are not unsafe, but members with pointers are.
// https://github.com/dotnet/roslyn/issues/81944: There is no error for the pointer even though `unsafe` is missing.
var libLegacy = CreateCompilation(
libSource)
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libLegacyRef = AsReference(libLegacy, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libLegacyRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,5): error CS9363: 'C.E.add' must be used in an unsafe context because it has pointers in its signature
// C.E += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "+=").WithArguments("C.E.add").WithLocation(1, 5))
.GetReferencedAssemblySymbol(libLegacyRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.E", "C.add_E", "C.remove_E"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Fact]
public void Extern_Event_Explicit()
{
CompileAndVerifyUnsafe(
lib: """
#pragma warning disable CS0626 // extern without attributes
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public static extern event System.Action E;
}
""",
caller: """
C.E += null;
C.E -= null;
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.E", "C.add_E", "C.remove_E"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,5): error CS9362: 'C.E.add' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.E += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "+=").WithArguments("C.E.add").WithLocation(1, 5),
// (2,5): error CS9362: 'C.E.remove' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// C.E -= null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "-=").WithArguments("C.E.remove").WithLocation(2, 5),
]);
}
[Fact]
public void Extern_Constructor()
{
var libSource = """
#pragma warning disable CS0824 // extern constructor
public class C
{
public extern C();
}
""";
var callerSource = """
_ = new C();
""";
object[] unsafeSymbols = ["C..ctor"];
var commonDiagnostics = new[]
{
// (1,5): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C()").WithArguments("C.C()").WithLocation(1, 5),
};
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics: commonDiagnostics);
CreateCompilation([libSource, callerSource],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics([
.. commonDiagnostics,
// (4,19): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern C();
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(4, 19),
]);
CreateCompilation([libSource, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,19): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern C();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("updated memory safety rules").WithLocation(4, 19));
CreateCompilation(libSource,
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Constructor_WithPointers()
{
static string getLibSource(string modifiers) => $$"""
#pragma warning disable CS0824 // extern constructor
public class C
{
public {{modifiers}} C(int* p);
}
""";
var callerSource = """
_ = new C(null);
""";
var libUpdated = CreateCompilation(
[getLibSource("extern"), RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libUpdatedRef = AsReference(libUpdated, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libUpdatedRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,5): error CS9362: 'C.C(int*)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C(null)").WithArguments("C.C(int*)").WithLocation(1, 5))
.GetReferencedAssemblySymbol(libUpdatedRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C..ctor"],
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: ["C..ctor"]);
}
CreateCompilation(getLibSource("extern")).VerifyDiagnostics(
// (4,21): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public extern C(int* p);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 21));
// When compiling the lib under legacy rules, extern members are not unsafe, but members with pointers are.
var libLegacy = CreateCompilation(
getLibSource("unsafe extern"),
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libLegacyRef = AsReference(libLegacy, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libLegacyRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,5): error CS9363: 'C.C(int*)' must be used in an unsafe context because it has pointers in its signature
// _ = new C(null);
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "new C(null)").WithArguments("C.C(int*)").WithLocation(1, 5))
.GetReferencedAssemblySymbol(libLegacyRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C..ctor"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Fact]
public void Extern_Constructor_Explicit()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public extern C();
}
""",
caller: """
_ = new C();
""",
additionalSources: [RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C..ctor"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (1,5): error CS9362: 'C.C()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// _ = new C();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C()").WithArguments("C.C()").WithLocation(1, 5),
]);
}
[Fact]
public void Extern_Operator()
{
var libSource = """
#pragma warning disable CS0626 // extern without attributes
public class C
{
public extern void operator +=(C c);
}
""";
var callerSource = """
var c = new C();
c += c;
""";
object[] unsafeSymbols = ["C.op_AdditionAssignment"];
var commonDiagnostics = new[]
{
// (2,1): error CS9362: 'C.operator +=(C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c += c;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c += c").WithArguments("C.operator +=(C)").WithLocation(2, 1),
};
CompileAndVerifyUnsafe(
libSource,
callerSource,
additionalSources: [CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: unsafeSymbols,
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: unsafeSymbols,
expectedNoAttributeUnderLegacyRules: unsafeSymbols,
expectedDiagnostics: commonDiagnostics);
CreateCompilation([libSource, callerSource, CompilerFeatureRequiredAttribute],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics([
.. commonDiagnostics,
// (4,33): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiresUnsafeAttribute..ctor'
// public extern void operator +=(C c);
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "+=").WithArguments("System.Runtime.CompilerServices.RequiresUnsafeAttribute", ".ctor").WithLocation(4, 33),
]);
CreateCompilation([libSource, CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (4,33): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public extern void operator +=(C c);
Diagnostic(ErrorCode.ERR_FeatureInPreview, "+=").WithArguments("updated memory safety rules").WithLocation(4, 33));
CreateCompilation([libSource, CompilerFeatureRequiredAttribute],
parseOptions: TestOptions.Regular14,
options: TestOptions.UnsafeReleaseDll)
.VerifyEmitDiagnostics();
}
[Fact]
public void Extern_Operator_WithPointers()
{
static string getLibSource(string modifiers) => $$"""
#pragma warning disable CS0626 // extern without attributes
public class C
{
public {{modifiers}} void operator +=(int* p);
}
""";
var callerSource = """
var c = new C();
c += null;
""";
var libUpdated = CreateCompilation(
[getLibSource("extern"), CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libUpdatedRef = AsReference(libUpdated, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libUpdatedRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9362: 'C.operator +=(int*)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c += null").WithArguments("C.operator +=(int*)").WithLocation(2, 1))
.GetReferencedAssemblySymbol(libUpdatedRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.op_AdditionAssignment"],
expectedSafeSymbols: ["C"],
expectedNoAttributeInSource: ["C.op_AdditionAssignment"]);
}
CreateCompilation([getLibSource("extern"), CompilerFeatureRequiredAttribute]).VerifyDiagnostics(
// (4,36): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// public extern void operator +=(int* p);
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(4, 36));
// When compiling the lib under legacy rules, extern members are not unsafe, but members with pointers are.
var libLegacy = CreateCompilation(
[getLibSource("unsafe extern"), CompilerFeatureRequiredAttribute],
options: TestOptions.UnsafeReleaseDll)
.VerifyDiagnostics();
foreach (var useCompilationReference in new[] { false, true })
{
var libLegacyRef = AsReference(libLegacy, useCompilationReference);
var libAssemblySymbol = CreateCompilation(callerSource,
[libLegacyRef],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (2,1): error CS9363: 'C.operator +=(int*)' must be used in an unsafe context because it has pointers in its signature
// c += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c += null").WithArguments("C.operator +=(int*)").WithLocation(2, 1))
.GetReferencedAssemblySymbol(libLegacyRef);
VerifyRequiresUnsafeAttribute(
libAssemblySymbol.Modules.Single(),
expectedUnsafeSymbols: ["C.op_AdditionAssignment"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.Implicit);
}
}
[Fact]
public void Extern_Operator_Explicit()
{
CompileAndVerifyUnsafe(
lib: """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public extern void operator +=(C c);
}
""",
caller: """
var c = new C();
c += null;
""",
additionalSources: [CompilerFeatureRequiredAttribute, RequiresUnsafeAttributeDefinition],
verify: Verification.Skipped,
expectedUnsafeSymbols: ["C.op_AdditionAssignment"],
expectedSafeSymbols: ["C"],
expectedDiagnostics:
[
// (2,1): error CS9362: 'C.operator +=(C)' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// c += null;
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c += null").WithArguments("C.operator +=(C)").WithLocation(2, 1),
]);
}
[Fact]
public void RequiresUnsafeAttribute_Applied()
{
var source = """
class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
void M1() { }
void M2() { }
}
""";
var expectedDiagnostics = new[]
{
// (3,6): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(3, 6),
};
CreateCompilation([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithWarningLevel(10))
.VerifyEmitDiagnostics();
CreateCompilation([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithWarningLevel(11))
.VerifyEmitDiagnostics(expectedDiagnostics);
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["C.M1"],
expectedSafeSymbols: ["C", "C.M2"],
expectedUnsafeMode: CallerUnsafeMode.None))
.VerifyDiagnostics(expectedDiagnostics);
var ref1 = CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["C.M1"],
expectedSafeSymbols: ["C", "C.M2"]))
.VerifyDiagnostics()
.GetImageReference();
CompileAndVerify("", [ref1],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [],
expectedSafeSymbols: []))
.VerifyDiagnostics();
var source2 = """
class B
{
void M3() { }
[System.Runtime.CompilerServices.RequiresUnsafe]
void M4() { }
}
""";
CompileAndVerify(source2, [ref1],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["B.M4"],
expectedSafeSymbols: ["B", "B.M3"]))
.VerifyDiagnostics();
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.ReleaseModule.WithAllowUnsafe(true).WithMetadataImportOptions(MetadataImportOptions.All),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["C.M1"],
expectedSafeSymbols: ["C", "C.M2"],
expectedUnsafeMode: CallerUnsafeMode.None))
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation([source, MemorySafetyRulesAttributeDefinition],
options: TestOptions.ReleaseModule.WithAllowUnsafe(true).WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,38): error CS0234: The type or namespace name 'RequiresUnsafeAttribute' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?)
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "RequiresUnsafe").WithArguments("RequiresUnsafeAttribute", "System.Runtime.CompilerServices").WithLocation(3, 38),
// (3,38): error CS0234: The type or namespace name 'RequiresUnsafe' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?)
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "RequiresUnsafe").WithArguments("RequiresUnsafe", "System.Runtime.CompilerServices").WithLocation(3, 38));
}
[Fact]
public void RequiresUnsafeAttribute_NotApplied()
{
var source = """
public class C
{
public void M() { }
}
""";
CompileAndVerify(source,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C", "C.M"]))
.VerifyDiagnostics();
CompileAndVerify(source,
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C", "C.M"]))
.VerifyDiagnostics();
CompileAndVerify([source, MemorySafetyRulesAttributeDefinition],
options: TestOptions.ReleaseModule.WithUpdatedMemorySafetyRules(),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [],
expectedSafeSymbols: ["C", "C.M"]))
.VerifyDiagnostics();
}
[Fact]
public void RequiresUnsafeAttribute_LocalFunction()
{
var source = """
#pragma warning disable CS8321 // Local function is declared but never used
class C
{
void M()
{
[System.Runtime.CompilerServices.RequiresUnsafe]
void M1() { }
void M2() { }
}
}
""";
var m1 = "C.<M>g__M1|0_0";
var m2 = "C.<M>g__M2|0_1";
var expectedDiagnostics = new[]
{
// (6,10): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(6, 10),
};
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [m1],
expectedSafeSymbols: [m2],
expectedUnsafeMode: CallerUnsafeMode.None))
.VerifyDiagnostics(expectedDiagnostics);
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [m1],
expectedSafeSymbols: [m2]))
.VerifyDiagnostics();
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.ReleaseModule.WithAllowUnsafe(true).WithMetadataImportOptions(MetadataImportOptions.All),
verify: Verification.Skipped,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [m1],
expectedSafeSymbols: [m2],
expectedUnsafeMode: CallerUnsafeMode.None))
.VerifyDiagnostics(expectedDiagnostics);
CreateCompilation([source, MemorySafetyRulesAttributeDefinition],
options: TestOptions.ReleaseModule.WithAllowUnsafe(true).WithUpdatedMemorySafetyRules())
.VerifyEmitDiagnostics(
// (6,42): error CS0234: The type or namespace name 'RequiresUnsafeAttribute' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?)
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "RequiresUnsafe").WithArguments("RequiresUnsafeAttribute", "System.Runtime.CompilerServices").WithLocation(6, 42),
// (6,42): error CS0234: The type or namespace name 'RequiresUnsafe' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?)
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "RequiresUnsafe").WithArguments("RequiresUnsafe", "System.Runtime.CompilerServices").WithLocation(6, 42));
}
[Fact]
public void RequiresUnsafeAttribute_Reflection()
{
var sourceA = """
using System;
using System.Linq;
using System.Reflection;
public class A
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M1() { }
public void M2() { }
public static void RequiresUnsafe(MethodInfo method)
{
var count = method.GetCustomAttributes(inherit: false).Count(a => a.GetType().Name == "RequiresUnsafeAttribute");
Console.Write(count);
}
}
""";
var refA = CreateCompilation([sourceA, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics()
.EmitToImageReference();
var sourceB = """
class B : A
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M3() { }
public void M4() { }
static void Main()
{
RequiresUnsafe(typeof(A).GetMethod("M1"));
RequiresUnsafe(typeof(A).GetMethod("M2"));
RequiresUnsafe(typeof(B).GetMethod("M3"));
RequiresUnsafe(typeof(B).GetMethod("M4"));
}
}
""";
CompileAndVerify(sourceB, [refA],
options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(),
expectedOutput: "1010")
.VerifyDiagnostics();
}
[Fact]
public void RequiresUnsafeAttribute_FromSource()
{
var source = """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M() { }
}
""";
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"],
expectedUnsafeMode: CallerUnsafeMode.None))
.VerifyDiagnostics(
// (3,6): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "System.Runtime.CompilerServices.RequiresUnsafe").WithLocation(3, 6));
CompileAndVerify([source, RequiresUnsafeAttributeDefinition],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"]))
.VerifyDiagnostics();
}
[Theory, CombinatorialData]
public void RequiresUnsafeAttribute_FromMetadata(bool useCompilationReference)
{
var comp = CreateCompilation(RequiresUnsafeAttributeDefinition);
CompileAndVerify(comp,
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: [],
expectedSafeSymbols: [AttributeDescription.RequiresUnsafeAttribute.FullName]))
.VerifyDiagnostics();
var ref1 = AsReference(comp, useCompilationReference);
var source = """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M() { }
}
""";
CompileAndVerify(source, [ref1],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules(),
symbolValidator: m => VerifyRequiresUnsafeAttribute(
m,
expectedUnsafeSymbols: ["C.M"],
expectedSafeSymbols: ["C"]))
.VerifyDiagnostics();
}
[Theory, CombinatorialData]
public void RequiresUnsafeAttribute_FromMetadata_Multiple(bool useCompilationReference)
{
var comp1 = CreateCompilation(RequiresUnsafeAttributeDefinition, assemblyName: "lib1").VerifyDiagnostics();
var ref1 = AsReference(comp1, useCompilationReference);
var comp2 = CreateCompilation(RequiresUnsafeAttributeDefinition, assemblyName: "lib2").VerifyDiagnostics();
var ref2 = AsReference(comp2, useCompilationReference);
var source = """
public class C
{
[System.Runtime.CompilerServices.RequiresUnsafe]
public void M() { }
}
""";
// Ambiguous attribute definitions from references.
CreateCompilation(source, [ref1, ref2],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,38): error CS0433: The type 'RequiresUnsafeAttribute' exists in both 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'lib2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.ERR_SameFullNameAggAgg, "RequiresUnsafe").WithArguments("lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "System.Runtime.CompilerServices.RequiresUnsafeAttribute", "lib2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 38));
// Also defined in source.
var lib = CreateCompilation([source, RequiresUnsafeAttributeDefinition], [ref1, ref2],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (3,38): warning CS0436: The type 'RequiresUnsafeAttribute' in '' conflicts with the imported type 'RequiresUnsafeAttribute' in 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// [System.Runtime.CompilerServices.RequiresUnsafe]
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "RequiresUnsafe").WithArguments("", "System.Runtime.CompilerServices.RequiresUnsafeAttribute", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "System.Runtime.CompilerServices.RequiresUnsafeAttribute").WithLocation(3, 38));
CreateCompilation("""
new C().M();
""",
[AsReference(lib, useCompilationReference)],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// new C().M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C().M()").WithArguments("C.M()").WithLocation(1, 1));
}
[Theory, CombinatorialData]
public void RequiresUnsafeAttribute_FromMetadata_Multiple_AndCorLib(bool useCompilationReference)
{
var corlibSource = """
namespace System
{
public class Object;
public class ValueType;
public class String;
public class Attribute;
public struct Void;
public struct Int32;
public struct Boolean;
public class AttributeUsageAttribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public class Enum;
public enum AttributeTargets;
}
namespace System.Runtime.CompilerServices
{
public sealed class RequiresUnsafeAttribute : Attribute;
}
""";
var corlib = CreateEmptyCompilation(corlibSource, assemblyName: "corlib").VerifyDiagnostics();
var corlibRef = AsReference(corlib, useCompilationReference);
var comp1 = CreateEmptyCompilation("", [corlibRef], assemblyName: "lib1").VerifyDiagnostics();
var ref1 = AsReference(comp1, useCompilationReference);
var comp2 = CreateEmptyCompilation("", [corlibRef], assemblyName: "lib2").VerifyDiagnostics();
var ref2 = AsReference(comp2, useCompilationReference);
var source = """
#pragma warning disable CS0626 // extern without attributes
public class C
{
public extern void M();
}
""";
// Using the attribute from corlib even if there are ambiguous definitions in other references.
var lib = CreateEmptyCompilation(source, [ref1, ref2, corlibRef],
options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules()
.WithSpecificDiagnosticOptions([KeyValuePair.Create("CS8021", ReportDiagnostic.Suppress)]))
.VerifyDiagnostics();
CreateEmptyCompilation("""
new C().M();
""",
[AsReference(lib, useCompilationReference), ref1, ref2, corlibRef],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// new C().M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "new C().M()").WithArguments("C.M()").WithLocation(1, 1));
}
[Fact]
public void RequiresUnsafeAttribute_FromMetadata_UnrecognizedConstructor()
{
// [module: MemorySafetyRules(2)]
// public class A
// {
// [RequiresUnsafe(1), RequiresUnsafe(0)]
// public static void M() => throw null;
// }
var sourceA = $$"""
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{CSharpCompilationOptions.UpdatedMemorySafetyRulesVersion}}) }
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class private System.Runtime.CompilerServices.RequiresUnsafeAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class public A
{
.method public static void M()
{
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor(int32) = { int32(1) }
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor(int32) = { int32(0) }
ldnull throw
}
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var a = CreateCompilation("", [refA]).VerifyDiagnostics().GetReferencedAssemblySymbol(refA);
Assert.Equal(CallerUnsafeMode.None, a.GlobalNamespace.GetMember("A.M").CallerUnsafeMode);
var sourceB = """
A.M();
""";
CreateCompilation(sourceB, [refA],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyEmitDiagnostics();
}
[Fact]
public void RequiresUnsafeAttribute_FromMetadata_UnrecognizedAndRecognizedConstructor()
{
// [module: MemorySafetyRules(2)]
// public class A
// {
// [RequiresUnsafe(1), RequiresUnsafe()]
// public static void M() => throw null;
// }
var sourceA = $$"""
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{CSharpCompilationOptions.UpdatedMemorySafetyRulesVersion}}) }
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class private System.Runtime.CompilerServices.RequiresUnsafeAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class public A
{
.method public static void M()
{
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor(int32) = { int32(1) }
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor()
ldnull throw
}
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var a = CreateCompilation("", [refA]).VerifyDiagnostics().GetReferencedAssemblySymbol(refA);
Assert.Equal(CallerUnsafeMode.Explicit, a.GlobalNamespace.GetMember("A.M").CallerUnsafeMode);
var sourceB = """
A.M();
""";
CreateCompilation(sourceB, [refA],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS9362: 'A.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// A.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "A.M()").WithArguments("A.M()").WithLocation(1, 1));
}
[Fact]
public void RequiresUnsafeAttribute_FromMetadata_AppliedMultipleTimes()
{
// [module: MemorySafetyRules(2)]
// public class A
// {
// [RequiresUnsafe, RequiresUnsafe]
// public static void M() => throw null;
// }
var sourceA = $$"""
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.MemorySafetyRulesAttribute::.ctor(int32) = { int32({{CSharpCompilationOptions.UpdatedMemorySafetyRulesVersion}}) }
.class private System.Runtime.CompilerServices.MemorySafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
}
.class private System.Runtime.CompilerServices.RequiresUnsafeAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public A
{
.method public static void M()
{
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor()
.custom instance void System.Runtime.CompilerServices.RequiresUnsafeAttribute::.ctor()
ldnull throw
}
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var a = CreateCompilation("", [refA]).VerifyDiagnostics().GetReferencedAssemblySymbol(refA);
Assert.Equal(CallerUnsafeMode.Explicit, a.GlobalNamespace.GetMember("A.M").CallerUnsafeMode);
var sourceB = """
A.M();
""";
CreateCompilation(sourceB, [refA],
options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules())
.VerifyDiagnostics(
// (1,1): error CS9362: 'A.M()' must be used in an unsafe context because it is marked as 'RequiresUnsafe' or 'extern'
// A.M();
Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "A.M()").WithArguments("A.M()").WithLocation(1, 1));
}
[Theory, CombinatorialData]
public void RequiresUnsafeAttribute_ReferencedInSource(
bool updatedRules,
bool useCompilationReference)
{
var comp1 = CreateCompilation("""
namespace System.Runtime.CompilerServices
{
public sealed class RequiresUnsafeAttribute : Attribute;
}
""").VerifyDiagnostics();
var ref1 = AsReference(comp1, useCompilationReference);
CSharpTestSource source =
[
"""
using System.Runtime.CompilerServices;
[RequiresUnsafeAttribute] class C
{
[RequiresUnsafeAttribute] void M() { }
[RequiresUnsafeAttribute] int P1 { get; set; }
[field: RequiresUnsafeAttribute] int P2 { get; set; }
int P3 { [RequiresUnsafeAttribute] get; [RequiresUnsafeAttribute] set; }
#pragma warning disable CS0067 // unused event
[RequiresUnsafeAttribute] event System.Action E1;
[field: RequiresUnsafeAttribute] event System.Action E2;
event System.Action E3 { [RequiresUnsafeAttribute] add { } [RequiresUnsafeAttribute] remove { } }
[RequiresUnsafeAttribute] int this[int i] { get => i; set { } }
[RequiresUnsafeAttribute] C() { }
[RequiresUnsafeAttribute] ~C() { }
[RequiresUnsafeAttribute] static C() { }
[RequiresUnsafeAttribute] public static C operator +(C c1, C c2) => c1;
[RequiresUnsafeAttribute] public void operator +=(C c) { }
public void M([RequiresUnsafeAttribute] int x) { }
[return: RequiresUnsafeAttribute] public int Func() => 0;
public void M<[RequiresUnsafeAttribute] T>() { }
#pragma warning disable CS0169 // unused field
[RequiresUnsafeAttribute] int F;
void L() { var lam = [RequiresUnsafeAttribute] () => { }; }
}
[RequiresUnsafeAttribute] delegate void D();
[RequiresUnsafeAttribute] enum E { X }
""", """
using System.Runtime.CompilerServices;
[module: RequiresUnsafeAttribute]
[assembly: RequiresUnsafeAttribute]
""",
CompilerFeatureRequiredAttribute,
];
var commonErrors = new[]
{
// (14,6): error CS9367: RequiresUnsafeAttribute cannot be applied to this symbol.
// [RequiresUnsafeAttribute] ~C() { }
Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeUnsupportedMemberTarget, "RequiresUnsafeAttribute").WithLocation(14, 6),
// (15,6): error CS9367: RequiresUnsafeAttribute cannot be applied to this symbol.
// [RequiresUnsafeAttribute] static C() { }
Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeUnsupportedMemberTarget, "RequiresUnsafeAttribute").WithLocation(15, 6),
// (23,27): error CS9367: RequiresUnsafeAttribute cannot be applied to this symbol.
// void L() { var lam = [RequiresUnsafeAttribute] () => { }; }
Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeUnsupportedMemberTarget, "RequiresUnsafeAttribute").WithLocation(23, 27),
};
var commonWarnings = new[]
{
// (4,6): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [RequiresUnsafeAttribute] void M() { }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(4, 6),
// (7,15): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// int P3 { [RequiresUnsafeAttribute] get; [RequiresUnsafeAttribute] set; }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(7, 15),
// (7,46): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// int P3 { [RequiresUnsafeAttribute] get; [RequiresUnsafeAttribute] set; }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(7, 46),
// (11,31): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// event System.Action E3 { [RequiresUnsafeAttribute] add { } [RequiresUnsafeAttribute] remove { } }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(11, 31),
// (11,65): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// event System.Action E3 { [RequiresUnsafeAttribute] add { } [RequiresUnsafeAttribute] remove { } }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(11, 65),
// (13,6): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [RequiresUnsafeAttribute] C() { }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(13, 6),
// (16,6): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [RequiresUnsafeAttribute] public static C operator +(C c1, C c2) => c1;
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(16, 6),
// (17,6): warning CS9368: RequiresUnsafeAttribute is only valid under the updated memory safety rules.
// [RequiresUnsafeAttribute] public void operator +=(C c) { }
Diagnostic(ErrorCode.WRN_RequiresUnsafeAttributeLegacyRules, "RequiresUnsafeAttribute").WithLocation(17, 6),
};
CreateCompilation(source, [ref1],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(updatedRules))
.VerifyDiagnostics(
[
.. commonErrors,
.. (updatedRules ? default(ReadOnlySpan<DiagnosticDescription>) : commonWarnings),
]);
var comp2 = CreateCompilation(RequiresUnsafeAttributeDefinition).VerifyDiagnostics();
var ref2 = AsReference(comp2, useCompilationReference);
CreateCompilation(source, [ref2],
options: TestOptions.ReleaseDll.WithUpdatedMemorySafetyRules(updatedRules))
.VerifyDiagnostics(
[
.. commonErrors,
.. (updatedRules ? default(ReadOnlySpan<DiagnosticDescription>) : commonWarnings),
// (3,12): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [assembly: RequiresUnsafeAttribute]
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(3, 12),
// (2,10): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [module: RequiresUnsafeAttribute]
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(2, 10),
// (2,2): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [RequiresUnsafeAttribute] class C
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(2, 2),
// (25,2): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [RequiresUnsafeAttribute] delegate void D();
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(25, 2),
// (26,2): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [RequiresUnsafeAttribute] enum E { X }
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(26, 2),
// (18,20): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// public void M([RequiresUnsafeAttribute] int x) { }
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(18, 20),
// (20,20): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// public void M<[RequiresUnsafeAttribute] T>() { }
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(20, 20),
// (6,13): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [field: RequiresUnsafeAttribute] int P2 { get; set; }
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(6, 13),
// (10,13): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [field: RequiresUnsafeAttribute] event System.Action E2;
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(10, 13),
// (19,14): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [return: RequiresUnsafeAttribute] public int Func() => 0;
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(19, 14),
// (22,6): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations.
// [RequiresUnsafeAttribute] int F;
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, event").WithLocation(22, 6),
]);
}
}
|