diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index f0145af5b1be2..ad55c59dd4b13 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -372,7 +372,7 @@ public override Binder VisitConversionOperatorDeclaration(ConversionOperatorDecl public override Binder VisitFieldDeclaration(FieldDeclarationSyntax parent) { - return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, isFieldDeclaration: true); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitEventDeclaration(EventDeclarationSyntax parent) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 92977d99539f7..1621424ef39d0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -517,7 +517,6 @@ void checkConstraintLanguageVersionAndRuntimeSupportForConversion(SyntaxNode syn Debug.Assert(elementField is { }); diagnostics.ReportUseSite(elementField, syntax); - AssertNotUnsafeMemberAccess(elementField); // https://github.com/dotnet/roslyn/issues/82546: Support unsafe fields? if (destination.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions)) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index d2e69288281cd..1b1ac8e02ad7b 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -9819,7 +9819,6 @@ BoundExpression bindInlineArrayElementAccess(ExpressionSyntax node, BoundExpress CheckFeatureAvailability(node, MessageID.IDS_FeatureInlineArrays, diagnostics); diagnostics.ReportUseSite(elementField, node); - AssertNotUnsafeMemberAccess(elementField); // https://github.com/dotnet/roslyn/issues/82546: Support unsafe fields? TypeSymbol resultType; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs index b2c1603fd99a6..14a7dfea50048 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs @@ -91,7 +91,7 @@ internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags return new BinderWithContainingMemberOrLambda(this, this.Flags | flags, containing); } - internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false, bool isFieldDeclaration = false) + internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false) { // In C# 13 and above, iterator bodies define a safe context even when nested in an unsafe context. // In C# 12 and below, we keep the (spec violating) behavior that iterator bodies inherit the safe/unsafe context @@ -107,9 +107,9 @@ internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, boo } // Under the updated memory safety rules, the `unsafe` modifier on a type or member declaration - // does not introduce an unsafe context (no interior meaning), except for field declarations. + // does not introduce an unsafe context (no interior meaning). // `unsafe { }` blocks also introduce an unsafe context. - return !withoutUnsafe && modifiers.Any(SyntaxKind.UnsafeKeyword) && (isFieldDeclaration || !this.Compilation.SourceModule.UseUpdatedMemorySafetyRules) + return !withoutUnsafe && modifiers.Any(SyntaxKind.UnsafeKeyword) && !this.Compilation.SourceModule.UseUpdatedMemorySafetyRules ? new Binder(this, this.Flags | BinderFlags.UnsafeRegion) : this; } diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs index ce7249178b2e2..7707ca2f9b4eb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/LambdaCapturedVariable.cs @@ -138,6 +138,8 @@ private static TypeSymbol GetCapturedVariableFieldType(SynthesizedContainer fram public override RefKind RefKind => RefKind.None; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs index 75a9449b34a00..3571a96b0338f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineFieldSymbol.cs @@ -63,6 +63,8 @@ internal override bool SuppressDynamicAttribute public override RefKind RefKind => RefKind.None; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs index d9bd6a604cebd..3d54b6b6c259d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs @@ -44,6 +44,8 @@ public override string Name public override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + internal override bool HasSpecialName { get { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs index 840562be89c1b..341314865036a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs @@ -336,8 +336,6 @@ internal virtual FieldSymbol AsMember(NamedTypeSymbol newOwner) /// internal abstract bool IsRequired { get; } - internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; // https://github.com/dotnet/roslyn/issues/82546: Support unsafe fields? - #region Use-Site Diagnostics internal override UseSiteInfo GetUseSiteInfo() diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs index 7a7c4371226fd..2c68664f89914 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs @@ -30,12 +30,13 @@ internal sealed class PEFieldSymbol : FieldSymbol private struct PackedFlags { // Layout: - // |........................|qq|rr|v|fffff| + // |......................|uu|qq|rr|v|fffff| // // f = FlowAnalysisAnnotations. 5 bits (4 value bits + 1 completion bit). // v = IsVolatile 1 bit // r = RefKind 2 bits // q = Required members. 2 bits (1 value bit + 1 completion bit). + // u = Requires unsafe. 2 bits (1 value bit + 1 completion bit). private const int HasDisallowNullAttribute = 0x1 << 0; private const int HasAllowNullAttribute = 0x1 << 1; @@ -48,6 +49,8 @@ private struct PackedFlags private const int HasRequiredMemberAttribute = 0x1 << 8; private const int RequiredMemberCompletionBit = 0x1 << 9; + private const int RequiresUnsafeBit = 0x1 << 10; + private const int RequiresUnsafeCompletionBit = 0x1 << 11; private int _bits; @@ -112,6 +115,24 @@ public bool TryGetHasRequiredMemberAttribute(out bool hasRequiredMemberAttribute hasRequiredMemberAttribute = false; return false; } + + public bool SetRequiresUnsafe(bool requiresUnsafe) + { + int bitsToSet = RequiresUnsafeCompletionBit | (requiresUnsafe ? RequiresUnsafeBit : 0); + return ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); + } + + public bool TryGetRequiresUnsafe(out bool requiresUnsafe) + { + if ((_bits & RequiresUnsafeCompletionBit) != 0) + { + requiresUnsafe = (_bits & RequiresUnsafeBit) != 0; + return true; + } + + requiresUnsafe = false; + return false; + } } private readonly FieldDefinitionHandle _handle; @@ -582,15 +603,17 @@ public override ImmutableArray GetAttributes() { if (RoslynImmutableInterlocked.VolatileRead(in _lazyCustomAttributes).IsDefault) { - var attributes = loadAndFilterAttributes(out var hasRequiredMemberAttribute); + var attributes = loadAndFilterAttributes(out var hasRequiredMemberAttribute, out var hasRequiresUnsafeAttribute); _packedFlags.SetHasRequiredMemberAttribute(hasRequiredMemberAttribute); + _packedFlags.SetRequiresUnsafe(ComputeRequiresUnsafe(hasRequiresUnsafeAttribute)); ImmutableInterlocked.InterlockedInitialize(ref _lazyCustomAttributes, attributes); } return _lazyCustomAttributes; - ImmutableArray loadAndFilterAttributes(out bool hasRequiredMemberAttribute) + ImmutableArray loadAndFilterAttributes(out bool hasRequiredMemberAttribute, out bool hasRequiresUnsafeAttribute) { hasRequiredMemberAttribute = false; + hasRequiresUnsafeAttribute = false; var containingModule = ContainingPEModule; if (!containingModule.TryGetNonEmptyCustomAttributes(_handle, out var customAttributeHandles)) @@ -611,6 +634,12 @@ ImmutableArray loadAndFilterAttributes(out bool hasRequired continue; } + if (containingModule.AttributeMatchesFilter(handle, AttributeDescription.RequiresUnsafeAttribute)) + { + hasRequiresUnsafeAttribute = true; + continue; + } + builder.Add(new PEAttributeData(containingModule, handle)); } @@ -713,5 +742,43 @@ internal override bool IsRequired return hasRequiredMemberAttribute; } } + + private bool RequiresUnsafe + { + get + { + if (!_packedFlags.TryGetRequiresUnsafe(out bool requiresUnsafe)) + { + bool hasRequiresUnsafeAttribute = ContainingPEModule.Module.HasAttribute(_handle, AttributeDescription.RequiresUnsafeAttribute); + requiresUnsafe = ComputeRequiresUnsafe(hasRequiresUnsafeAttribute); + _packedFlags.SetRequiresUnsafe(requiresUnsafe); + } + + return requiresUnsafe; + } + } + + private bool ComputeRequiresUnsafe(bool hasRequiresUnsafeAttribute) + { + return ContainingModule.UseUpdatedMemorySafetyRules + ? hasRequiresUnsafeAttribute + // This might be expensive, so we cache it in _packedFlags. + : !IsFixedSizeBuffer && Type.ContainsPointerOrFunctionPointer(); + } + + internal sealed override CallerUnsafeMode CallerUnsafeMode + { + get + { + if (!RequiresUnsafe) + { + return CallerUnsafeMode.None; + } + + return ContainingModule.UseUpdatedMemorySafetyRules + ? CallerUnsafeMode.Explicit + : CallerUnsafeMode.Implicit; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingFieldSymbol.cs index 68f9f0b5a1277..1b6908f2140cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingFieldSymbol.cs @@ -118,6 +118,8 @@ public override Symbol AssociatedSymbol } } + internal sealed override CallerUnsafeMode CallerUnsafeMode => _underlyingField.CallerUnsafeMode; + public override int TupleElementIndex => _underlyingField.TupleElementIndex; internal override UseSiteInfo GetUseSiteInfo() diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs index 66dd6663a5b47..df686f7113c57 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs @@ -203,6 +203,10 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut { MarshalAsAttributeDecoder.Decode(ref arguments, AttributeTargets.Field, MessageProvider.Instance); } + else if (attribute.IsTargetAttribute(AttributeDescription.RequiresUnsafeAttribute)) + { + diagnostics.Add(ErrorCode.ERR_RequiresUnsafeAttributeInSource, arguments.AttributeSyntaxOpt.Location); + } else if (ReportExplicitUseOfReservedAttributes(in arguments, ReservedAttributes.DynamicAttribute | ReservedAttributes.IsReadOnlyAttribute diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs index 7cd6903b411ee..4564e23239642 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs @@ -58,6 +58,8 @@ protected SourceEnumConstantSymbol(SourceMemberContainerTypeSymbol containingEnu public sealed override RefKind RefKind => RefKind.None; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) { return TypeWithAnnotations.Create(this.ContainingType); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 88284d93e2de1..63a92f6b9df7d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -137,6 +137,21 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r ref attributes, this.DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor)); } + + if (CallerUnsafeMode == CallerUnsafeMode.Explicit) + { + AddSynthesizedAttribute(ref attributes, moduleBuilder.TrySynthesizeRequiresUnsafeAttribute()); + } + } + + internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, BindingDiagnosticBag diagnostics) + { + if (CallerUnsafeMode == CallerUnsafeMode.Explicit) + { + DeclaringCompilation.EnsureRequiresUnsafeAttributeExists(diagnostics, ModifiersTokenList.GetUnsafeOrExternLocation(ErrorLocation), modifyCompilation: true); + } + + base.AfterAddingTypeMembersChecks(conversions, diagnostics); } internal override void PostDecodeWellKnownAttributes(ImmutableArray boundAttributes, ImmutableArray allAttributeSyntaxNodes, BindingDiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData) @@ -173,6 +188,24 @@ public override int FixedSize } } + internal sealed override CallerUnsafeMode CallerUnsafeMode + { + get + { + if (ContainingModule.UseUpdatedMemorySafetyRules) + { + return (Modifiers & DeclarationModifiers.Unsafe) != 0 && + AssociatedSymbol is null && + !IsConst + ? CallerUnsafeMode.Explicit + : CallerUnsafeMode.None; + } + + return !IsFixedSizeBuffer && Type.ContainsPointerOrFunctionPointer() + ? CallerUnsafeMode.Implicit : CallerUnsafeMode.None; + } + } + internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingType, SyntaxToken firstIdentifier, SyntaxTokenList modifiers, bool isRefField, BindingDiagnosticBag diagnostics, out bool modifierErrors) { bool isInterface = containingType.IsInterface; diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs index 0fb488352ade3..fe5aac7cf9e57 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs @@ -94,6 +94,8 @@ public override Symbol AssociatedSymbol } } + internal sealed override CallerUnsafeMode CallerUnsafeMode => _underlyingField.CallerUnsafeMode; + internal override NamedTypeSymbol FixedImplementationType(PEModuleBuilder emitModule) { // This occurs rarely, if ever. The scenario would be a generic struct diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs index 18e3b4b1024b0..13e3f342c553e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructorParameterBackingFieldSymbol.cs @@ -47,6 +47,8 @@ public override ImmutableArray Locations public override RefKind RefKind => RefKind.None; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index 78ef3fcc9724b..7084aae0371cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -124,6 +124,8 @@ public override Location TryGetFirstLocation() public override RefKind RefKind => _property.RefKind; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + public override ImmutableArray RefCustomModifiers => _property.RefCustomModifiers; internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs index a96661abbc1ec..741e40ee19841 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEnumValueFieldSymbol.cs @@ -26,6 +26,8 @@ internal override bool SuppressDynamicAttribute get { return true; } } + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + public override RefKind RefKind => RefKind.None; public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbol.cs index da88499e9c46a..b9975d4443876 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbol.cs @@ -42,6 +42,8 @@ internal override bool SuppressDynamicAttribute get { return true; } } + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) { return _type; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLambdaCacheFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLambdaCacheFieldSymbol.cs index 7d38a5f52a60d..8ae5479539ff7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLambdaCacheFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedLambdaCacheFieldSymbol.cs @@ -27,6 +27,8 @@ public SynthesizedLambdaCacheFieldSymbol(NamedTypeSymbol containingType, TypeSym internal override bool SuppressDynamicAttribute => true; + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + IMethodSymbolInternal ISynthesizedMethodBodyImplementationSymbol.Method => _topLevelMethod; // When the containing top-level method body is updated we don't need to attempt to update the cache field diff --git a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleErrorFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleErrorFieldSymbol.cs index 6e253a1e3e88f..5a5e1719055b2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleErrorFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleErrorFieldSymbol.cs @@ -154,6 +154,8 @@ internal override bool SuppressDynamicAttribute } } + internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; + public override RefKind RefKind => RefKind.None; public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs index fefe15ed6d442..fa15213e5048b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs @@ -124,6 +124,8 @@ public sealed override Symbol ContainingSymbol public sealed override RefKind RefKind => _underlyingField.RefKind; + internal sealed override CallerUnsafeMode CallerUnsafeMode => _underlyingField.CallerUnsafeMode; + public sealed override ImmutableArray RefCustomModifiers => _underlyingField.RefCustomModifiers; internal override TypeWithAnnotations GetFieldType(ConsList fieldsBeingBound) diff --git a/src/Compilers/CSharp/Test/CSharp15/UnsafeEvolutionTests.cs b/src/Compilers/CSharp/Test/CSharp15/UnsafeEvolutionTests.cs index 030745d8f0fd7..5951e58b2c3b2 100644 --- a/src/Compilers/CSharp/Test/CSharp15/UnsafeEvolutionTests.cs +++ b/src/Compilers/CSharp/Test/CSharp15/UnsafeEvolutionTests.cs @@ -334,6 +334,7 @@ void verifyAttributeInMetadata(Symbol s, bool shouldHave) EntityHandle? handle = s switch { PEMethodSymbol m => (EntityHandle?)m.Handle, + PEFieldSymbol f => f.Handle, PEPropertySymbol p => p.Handle, PEEventSymbol e => e.Handle, _ => null, @@ -3090,6 +3091,51 @@ struct S Diagnostic(ErrorCode.ERR_FeatureInPreview, "x[5]").WithArguments("updated memory safety rules").WithLocation(7, 22)); } + [Fact] + public void FixedSizeBuffer_Unsafe() + { + var expectedFixedBufferDiagnosticsForLegacyCaller = new[] + { + // (3,12): error CS9360: This operation may only be used in an unsafe context + // int z = s.x[0]; + Diagnostic(ErrorCode.ERR_UnsafeOperation, "[").WithLocation(3, 12), + }; + + CompileAndVerifyUnsafe( + lib: """ + public struct S + { + public unsafe fixed int x[5], y[10]; + } + """, + caller: """ + var s = new S(); + int* p = s.y; + int z = s.x[0]; + unsafe + { + p = s.y; + z = s.x[0]; + } + """, + expectedUnsafeSymbols: ["S.x", "S.y"], + expectedSafeSymbols: ["S"], + expectedDiagnostics: + [ + // (2,10): error CS9362: 'S.y' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // int* p = s.y; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "s.y").WithArguments("S.y").WithLocation(2, 10), + // (3,9): error CS9362: 'S.x' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // int z = s.x[0]; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "s.x").WithArguments("S.x").WithLocation(3, 9), + // (3,12): error CS9360: This operation may only be used in an unsafe context + // int z = s.x[0]; + Diagnostic(ErrorCode.ERR_UnsafeOperation, "[").WithLocation(3, 12), + ], + expectedDiagnosticsWhenReferencingLegacyLib: expectedFixedBufferDiagnosticsForLegacyCaller, + expectedDiagnosticsForLegacyCaller: expectedFixedBufferDiagnosticsForLegacyCaller); + } + [Fact] public void SkipLocalsInit_NeedsUnsafe() { @@ -3579,6 +3625,9 @@ unsafe class D // (4,49): error CS9360: This operation may only be used in an unsafe context // unsafe int P1 { get { int* p = null; return *p; } } Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(4, 49), + // (6,20): error CS9360: This operation may only be used in an unsafe context + // unsafe int f = *(default(int*)); + Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(6, 20), // (8,14): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. // unsafe class D Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "D").WithLocation(8, 14), @@ -3980,15 +4029,13 @@ CSharpCompilation createCompilation(CSharpCompilationOptions options) } [Fact] - public void Member_LangVersion() + public void Member_UnsafeDeclarations() { - CSharpTestSource source = - [ - """ + var declarationsSource = """ #pragma warning disable CS8321 // unused local function - unsafe void F() { } class C { + void M0() { unsafe void F() { } } unsafe void M() { } unsafe int P { get; set; } @@ -4002,7 +4049,10 @@ unsafe C() { } } unsafe class U; unsafe delegate void D(); - """, + """; + CSharpTestSource source = + [ + declarationsSource, CompilerFeatureRequiredAttribute, """ namespace System.Diagnostics.CodeAnalysis @@ -4012,10 +4062,10 @@ public sealed class RequiresUnsafeAttribute : Attribute; """, ]; - string[] safeSymbols = ["C", "C.F", "U", "D"]; + string[] safeSymbols = ["C", "U", "D"]; string[] unsafeSymbols = [ - "Program.<
$>g__F|0_0", + "C.g__F|0_0", "C.M", "C.P", "C.get_P", "C.set_P", "C.E", "C.add_E", "C.remove_E", @@ -4023,13 +4073,14 @@ public sealed class RequiresUnsafeAttribute : Attribute; "C..ctor", "C.op_Addition", "C.op_AdditionAssignment", + "C.F", ]; foreach (var parseOptions in new[] { TestOptions.RegularPreview, TestOptions.RegularNext, TestOptions.Regular14 }) { CompileAndVerify(source, parseOptions: parseOptions, - options: TestOptions.UnsafeReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All), + options: TestOptions.UnsafeReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m => { VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false); @@ -4047,7 +4098,7 @@ public sealed class RequiresUnsafeAttribute : Attribute; { CompileAndVerify(source, parseOptions: parseOptions, - options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All), + options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules().WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m => { VerifyMemorySafetyRulesAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, isSynthesized: true); @@ -4069,7 +4120,7 @@ public sealed class RequiresUnsafeAttribute : Attribute; CreateCompilation(source, parseOptions: TestOptions.Regular14, - options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()) + options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules()) .VerifyDiagnostics( // error CS8630: Invalid 'MemorySafetyRules' value: '2' for C# 14.0. Please use language version 'preview' or greater. Diagnostic(ErrorCode.ERR_CompilationOptionNotAvailable).WithArguments("MemorySafetyRules", "2", "14.0", "preview").WithLocation(1, 1), @@ -4079,6 +4130,68 @@ public sealed class RequiresUnsafeAttribute : Attribute; // (17,22): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. // unsafe delegate void D(); Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "D").WithLocation(17, 22)); + + source = + [ + declarationsSource, + CompilerFeatureRequiredAttribute, + MemorySafetyRulesAttributeDefinition, + ]; + + CreateCompilation(source, + options: TestOptions.ReleaseModule.WithAllowUnsafe(true).WithUpdatedMemorySafetyRules()) + .VerifyDiagnostics( + // (4,17): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // void M0() { unsafe void F() { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(4, 17), + // (5,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe void M() { } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(5, 5), + // (6,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int P { get; set; } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(6, 5), + // (6,20): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int P { get; set; } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "get").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(6, 20), + // (6,25): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int P { get; set; } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "set").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(6, 25), + // (8,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(8, 5), + // (8,36): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "add").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(8, 36), + // (8,44): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe event System.Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "remove").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(8, 44), + // (9,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int this[int i] { get => i; set { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(9, 5), + // (9,30): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int this[int i] { get => i; set { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "get").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(9, 30), + // (9,40): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int this[int i] { get => i; set { } } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "set").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(9, 40), + // (10,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe C() { } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(10, 5), + // (11,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe public static C operator +(C c1, C c2) => c1; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(11, 5), + // (12,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe public void operator +=(C c) { } + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(12, 5), + // (14,5): error CS0518: Predefined type 'System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute' is not defined or imported + // unsafe int F; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unsafe").WithArguments("System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute").WithLocation(14, 5), + // (16,14): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. + // unsafe class U; + Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "U").WithLocation(16, 14), + // (17,22): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. + // unsafe delegate void D(); + Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "D").WithLocation(17, 22)); } [Theory, CombinatorialData] @@ -6745,61 +6858,74 @@ public class A : System.Attribute public int P3 { unsafe get; set; } public int P4 { get; unsafe set; } public unsafe int F; + public int G; } """, 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; + [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] class C1; + [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] unsafe class C2; partial class C3 { - [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M1() { } + [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M1() { } } unsafe partial class C3 { - [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M2() { } + [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M2() { } } """, - 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"], + expectedUnsafeSymbols: ["A.P2", "A.get_P2", "A.set_P2", "A.get_P3", "A.set_P4", "A.F"], + expectedSafeSymbols: ["A.P1", "A.get_P1", "A.set_P1", "A.set_P3", "A.get_P4", "A.G"], expectedDiagnostics: [ // (2,12): error CS9362: 'A.P2.set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] class C1; + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 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 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] class C1; + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] class C1; Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P4 = 0").WithArguments("A.P4.set").WithLocation(2, 28), + // (2,36): error CS9362: 'A.F' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] class C1; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "F = 0").WithArguments("A.F").WithLocation(2, 36), // (3,12): error CS9362: 'A.P2.set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] unsafe class C2; + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] unsafe class C2; Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P2 = 0").WithArguments("A.P2.set").WithLocation(3, 12), // (3,28): error CS9362: 'A.P4.set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] unsafe class C2; + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] unsafe class C2; Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P4 = 0").WithArguments("A.P4.set").WithLocation(3, 28), - // (3,57): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] unsafe class C2; - Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "C2").WithLocation(3, 57), + // (3,36): error CS9362: 'A.F' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] unsafe class C2; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "F = 0").WithArguments("A.F").WithLocation(3, 36), + // (3,64): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] unsafe class C2; + Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "C2").WithLocation(3, 64), // (4,15): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. // partial class C3 Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "C3").WithLocation(4, 15), // (6,16): error CS9362: 'A.P2.set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M1() { } + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 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 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M1() { } + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M1() { } Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P4 = 0").WithArguments("A.P4.set").WithLocation(6, 32), + // (6,40): error CS9362: 'A.F' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M1() { } + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "F = 0").WithArguments("A.F").WithLocation(6, 40), // (10,16): error CS9362: 'A.P2.set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M2() { } + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M2() { } Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P2 = 0").WithArguments("A.P2.set").WithLocation(10, 16), // (10,32): error CS9362: 'A.P4.set' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] void M2() { } + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M2() { } Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "P4 = 0").WithArguments("A.P4.set").WithLocation(10, 32), + // (10,40): error CS9362: 'A.F' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] void M2() { } + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "F = 0").WithArguments("A.F").WithLocation(10, 40), ], expectedDiagnosticsWhenReferencingLegacyLib: [ - // (3,57): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. - // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0)] unsafe class C2; - Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "C2").WithLocation(3, 57), + // (3,64): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. + // [A(P1 = 0, P2 = 0, P3 = 0, P4 = 0, F = 0, G = 0)] unsafe class C2; + Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "C2").WithLocation(3, 64), // (4,15): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. // partial class C3 Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "C3").WithLocation(4, 15), @@ -8494,6 +8620,9 @@ public unsafe class C [libRef], options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()) .VerifyDiagnostics( + // (2,12): error CS9363: 'C.F' must be used in an unsafe context because it has pointers in its signature + // string s = c.F(); + Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.F").WithArguments("C.F").WithLocation(2, 12), // (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)); @@ -8507,8 +8636,8 @@ public unsafe class C verify: Verification.Skipped, symbolValidator: m => VerifyRequiresUnsafeAttribute( m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(), - expectedUnsafeSymbols: [], - expectedSafeSymbols: ["C", "C.F", (object)getFunctionPointerType, (object)getFunctionPointerMethod], + expectedUnsafeSymbols: ["C.F"], + expectedSafeSymbols: ["C", (object)getFunctionPointerType, (object)getFunctionPointerMethod], expectedUnsafeMode: CallerUnsafeMode.Implicit, includesAttributeDefinition: false)) .VerifyDiagnostics(); @@ -8551,6 +8680,193 @@ static Symbol getFunctionPointerMethod(ModuleSymbol module) } } + [Fact] + public void Member_Field() + { + CompileAndVerifyUnsafe( + lib: """ + public class C + { + public int F1; + unsafe public int F2; + public static int F3; + unsafe public static int F4; + public const int F5 = 0; + } + """, + caller: """ + var c = new C(); + _ = c.F1; + _ = c.F2; + _ = C.F3; + _ = C.F4; + _ = C.F5; + c.F1 = 1; + c.F2 = 2; + C.F3 = 3; + C.F4 = 4; + _ = new C { F1 = 1, F2 = 2 }; + unsafe + { + _ = c.F2; + _ = C.F4; + c.F2 = 2; + C.F4 = 4; + _ = new C { F2 = 2 }; + } + """, + expectedUnsafeSymbols: ["C.F2", "C.F4"], + expectedSafeSymbols: ["C", "C.F1", "C.F3", "C.F5"], + expectedDiagnostics: + [ + // (3,5): error CS9362: 'C.F2' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // _ = c.F2; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.F2").WithArguments("C.F2").WithLocation(3, 5), + // (5,5): error CS9362: 'C.F4' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // _ = C.F4; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.F4").WithArguments("C.F4").WithLocation(5, 5), + // (8,1): error CS9362: 'C.F2' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // c.F2 = 2; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "c.F2").WithArguments("C.F2").WithLocation(8, 1), + // (10,1): error CS9362: 'C.F4' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // C.F4 = 4; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.F4").WithArguments("C.F4").WithLocation(10, 1), + // (11,21): error CS9362: 'C.F2' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // _ = new C { F1 = 1, F2 = 2 }; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "F2").WithArguments("C.F2").WithLocation(11, 21), + ]); + + CreateCompilation(""" + public class C + { + unsafe public const int F = 0; + } + """, + options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules()) + .VerifyDiagnostics( + // (3,29): error CS0106: The modifier 'unsafe' is not valid for this item + // unsafe public const int F = 0; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F").WithArguments("unsafe").WithLocation(3, 29)); + } + + [Fact] + public void Member_Field_PointerType() + { + var source = """ + var c = new C(); + _ = c.F1; + _ = c.F2; + c.F2 = default; + _ = c.F3; + c.F3 = default; + _ = new C { F2 = default, F3 = default }; + + public class C + { + public int F1; + public int* F2; + public delegate* F3; + } + """; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithUpdatedMemorySafetyRules()); + comp.VerifyDiagnostics(); + VerifyRequiresUnsafeAttribute( + comp.SourceModule, + expectedUnsafeSymbols: [], + expectedSafeSymbols: ["C", "C.F1", "C.F2", "C.F3"], + includesAttributeDefinition: false); + } + + [Fact] + public void Member_Field_Enum() + { + CompileAndVerifyUnsafe( + lib: """ + public enum E + { + A, + B, + } + """, + caller: """ + _ = E.A; + _ = E.B; + """, + expectedUnsafeSymbols: [], + expectedSafeSymbols: ["E", "E.A", "E.B"], + expectedDiagnostics: []); + + CreateCompilation(""" + public enum E + { + unsafe A, + } + """, + options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules()) + .VerifyDiagnostics( + // (2,2): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 2), + // (3,12): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // unsafe A, + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "A").WithLocation(3, 12), + // (3,13): error CS1022: Type or namespace definition, or end-of-file expected + // unsafe A, + Diagnostic(ErrorCode.ERR_EOFExpected, ",").WithLocation(3, 13), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + } + + /// + /// The compiler does not actually use the inline array's field, hence there is no diagnostic. + /// + [Fact] + public void Member_Field_InlineArray() + { + var source = """ + using System; + + class Program + { + static void M(Buffer buffer, int index) + { + _ = buffer[index]; + _ = buffer[..]; + Span span = buffer; + ReadOnlySpan readOnlySpan = buffer; + + unsafe + { + _ = buffer[index]; + _ = buffer[..]; + Span unsafeSpan = buffer; + ReadOnlySpan unsafeReadOnlySpan = buffer; + } + } + } + + [System.Runtime.CompilerServices.InlineArray(3)] + public struct Buffer + { + unsafe private int _element0; + } + """; + + CreateCompilation( + source, + targetFramework: TargetFramework.Net100, + options: TestOptions.UnsafeReleaseDll) + .VerifyEmitDiagnostics(); + + CreateCompilation( + source, + targetFramework: TargetFramework.Net100, + options: TestOptions.UnsafeReleaseDll.WithUpdatedMemorySafetyRules()) + .VerifyEmitDiagnostics(); + } + [Fact] public void Member_Field_UnsafeInitializer() { @@ -8587,6 +8903,12 @@ unsafe class U // (5,14): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' // int F2 = C.M(); Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M()").WithArguments("C.M()").WithLocation(5, 14), + // (7,21): error CS9360: This operation may only be used in an unsafe context + // unsafe int U1 = *default(int*); + Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(7, 21), + // (8,21): error CS9362: 'C.M()' must be used in an unsafe context because it is marked as 'unsafe' or 'extern' + // unsafe int U2 = C.M(); + Diagnostic(ErrorCode.ERR_UnsafeMemberOperation, "C.M()").WithArguments("C.M()").WithLocation(8, 21), // (10,14): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. // unsafe class U Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "U").WithLocation(10, 14), @@ -8617,6 +8939,9 @@ unsafe class U // (4,14): error CS9360: This operation may only be used in an unsafe context // int F1 = *default(int*); Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(4, 14), + // (7,21): error CS9360: This operation may only be used in an unsafe context + // unsafe int U1 = *default(int*); + Diagnostic(ErrorCode.ERR_UnsafeOperation, "*").WithLocation(7, 21), // (10,14): warning CS9377: The 'unsafe' modifier does not have any effect here under the current memory safety rules. // unsafe class U Diagnostic(ErrorCode.WRN_UnsafeMeaningless, "U").WithLocation(10, 14), @@ -8626,6 +8951,102 @@ unsafe class U ]); } + [Theory, CombinatorialData] + public void CompatMode_Field( + [CombinatorialValues("int*", "int*[]", "delegate*")] string type, + bool useCompilationReference) + { + var lib = CreateCompilation($$""" + public class C + { + public unsafe int F1; + public unsafe {{type}} F2; + } + """, + options: TestOptions.UnsafeReleaseDll, + assemblyName: "lib") + .VerifyDiagnostics(); + var libRef = AsReference(lib, useCompilationReference); + + var source = """ + var c = new C(); + _ = c.F1; + _ = c.F2; + c.F2 = default; + _ = new C { F2 = default }; + unsafe + { + _ = c.F2; + c.F2 = default; + _ = new C { F2 = default }; + } + """; + + CreateCompilation(source, + [libRef], + options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules()) + .VerifyDiagnostics( + // (3,5): error CS9363: 'C.F2' must be used in an unsafe context because it has pointers in its signature + // _ = c.F2; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.F2").WithArguments("C.F2").WithLocation(3, 5), + // (4,1): error CS9363: 'C.F2' must be used in an unsafe context because it has pointers in its signature + // c.F2 = default; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "c.F2").WithArguments("C.F2").WithLocation(4, 1), + // (5,13): error CS9363: 'C.F2' must be used in an unsafe context because it has pointers in its signature + // _ = new C { F2 = default }; + Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "F2").WithArguments("C.F2").WithLocation(5, 13)); + + CompileAndVerify(""" + var c = new C(); + _ = c.F1; + unsafe + { + _ = c.F2; + c.F2 = default; + _ = new C { F2 = default }; + } + """, + [libRef], + options: TestOptions.UnsafeReleaseExe.WithUpdatedMemorySafetyRules(), + verify: Verification.Skipped, + symbolValidator: m => VerifyRequiresUnsafeAttribute( + m.ReferencedAssemblySymbols.Single(a => a.Name == "lib").Modules.Single(), + expectedUnsafeSymbols: ["C.F2"], + expectedSafeSymbols: ["C", "C.F1"], + expectedUnsafeMode: CallerUnsafeMode.Implicit, + includesAttributeDefinition: false)) + .VerifyDiagnostics(); + + CreateCompilation(source, + [libRef], + parseOptions: TestOptions.Regular14, + options: TestOptions.UnsafeReleaseExe) + .VerifyDiagnostics( + // (3,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // _ = c.F2; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "_ = c.F2").WithLocation(3, 1), + // (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // _ = c.F2; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.F2").WithLocation(3, 5), + // (4,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // c.F2 = default; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.F2").WithLocation(4, 1), + // (4,1): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // c.F2 = default; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "c.F2 = default").WithLocation(4, 1)); + + CreateCompilation(source, + [libRef], + options: TestOptions.UnsafeReleaseExe) + .VerifyDiagnostics(); + + CreateCompilation(source, + [libRef], + parseOptions: TestOptions.RegularNext, + options: TestOptions.UnsafeReleaseExe) + .VerifyDiagnostics(); + } + [Theory, CombinatorialData] public void CompatMode_Method_ParameterType( [CombinatorialValues("int*", "int*[]", "delegate*")] string parameterType, @@ -11731,6 +12152,7 @@ public void M<[RequiresUnsafeAttribute] T>() { } } [RequiresUnsafeAttribute] delegate void D(); [RequiresUnsafeAttribute] enum E { X } + enum F { [RequiresUnsafeAttribute] X } """, """ using System.Diagnostics.CodeAnalysis; [module: RequiresUnsafeAttribute] @@ -11747,6 +12169,9 @@ [RequiresUnsafeAttribute] enum E { X } // (5,6): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. // [RequiresUnsafeAttribute] int P1 { get; set; } Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(5, 6), + // (6,13): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. + // [field: RequiresUnsafeAttribute] int P2 { get; set; } + Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(6, 13), // (7,15): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. // int P3 { [RequiresUnsafeAttribute] get; [RequiresUnsafeAttribute] set; } Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(7, 15), @@ -11756,6 +12181,9 @@ [RequiresUnsafeAttribute] enum E { X } // (9,6): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. // [RequiresUnsafeAttribute] event System.Action E1; Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(9, 6), + // (10,13): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. + // [field: RequiresUnsafeAttribute] event System.Action E2; + Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(10, 13), // (11,31): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. // event System.Action E3 { [RequiresUnsafeAttribute] add { } [RequiresUnsafeAttribute] remove { } } Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(11, 31), @@ -11783,6 +12211,12 @@ [RequiresUnsafeAttribute] enum E { X } // (23,27): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. // void L() { var lam = [RequiresUnsafeAttribute] () => { }; } Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(23, 27), + // (22,6): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. + // [RequiresUnsafeAttribute] int F; + Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(22, 6), + // (27,11): error CS9379: Do not use 'RequiresUnsafeAttribute' in source; use the 'unsafe' modifier instead. + // enum F { [RequiresUnsafeAttribute] X } + Diagnostic(ErrorCode.ERR_RequiresUnsafeAttributeInSource, "RequiresUnsafeAttribute").WithLocation(27, 11), }; CreateCompilation(source, [ref1], @@ -11800,39 +12234,30 @@ [RequiresUnsafeAttribute] enum E { X } .VerifyDiagnostics( [ .. sourceErrors, - // (3,12): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, event' declarations. + // (3,12): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, 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, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, 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, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, 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, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, 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, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, 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, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, 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, field, 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. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, event").WithLocation(20, 20), + // (19,14): error CS0592: Attribute 'RequiresUnsafeAttribute' is not valid on this declaration type. It is only valid on 'constructor, method, property, indexer, field, 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), + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "RequiresUnsafeAttribute").WithArguments("RequiresUnsafeAttribute", "constructor, method, property, indexer, field, event").WithLocation(19, 14), ]); } diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 5121a50908f67..7e49420f04e7c 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -715,7 +715,7 @@ public sealed class MemorySafetyRulesAttribute : Attribute protected static readonly string RequiresUnsafeAttributeDefinition = """ namespace System.Diagnostics.CodeAnalysis { - [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] + [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class RequiresUnsafeAttribute : Attribute { } } """; diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs index 89fbcefb98436..e3eab4efc3c09 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs @@ -219,6 +219,8 @@ internal override TypeWithAnnotations GetFieldType(ConsList fieldsB public override RefKind RefKind => RefKind.None; public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; + + internal override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None; } } }