Thanks to visit codestin.com
Credit goes to github.com

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ internal bool InUnsafeRegion

private void ReportDiagnosticsIfUnsafeMemberAccess(BindingDiagnosticBag diagnostics, Symbol symbol, SyntaxNode node)
{
if (symbol.IsCallerUnsafe)
var callerUnsafeMode = symbol.CallerUnsafeMode;
if (callerUnsafeMode != CallerUnsafeMode.None)
{
ReportUnsafeIfNotAllowed(node, diagnostics, disallowedUnder: MemorySafetyRules.Updated,
customErrorCode: ErrorCode.ERR_UnsafeMemberOperation,
customErrorCode: callerUnsafeMode switch
{
CallerUnsafeMode.Explicit => ErrorCode.ERR_UnsafeMemberOperation,
CallerUnsafeMode.Implicit => ErrorCode.ERR_UnsafeMemberOperationCompat,
_ => throw ExceptionUtilities.UnexpectedValue(callerUnsafeMode),
},
customArgs: [symbol]);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -8194,4 +8194,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>'{0}' must be used in an unsafe context because it is marked as 'unsafe'</value>
<comment>'unsafe' is a keyword, should not be localized.</comment>
</data>
<data name="ERR_UnsafeMemberOperationCompat" xml:space="preserve">
<value>'{0}' must be used in an unsafe context because it has pointers in its signature</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2455,5 +2455,6 @@ internal enum ErrorCode
ERR_UnsafeOperation = 9500,
ERR_UnsafeUninitializedStackAlloc = 9501,
ERR_UnsafeMemberOperation = 9502,
ERR_UnsafeMemberOperationCompat = 9503,
}
}
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ or ErrorCode.ERR_NonTaskMainCantBeAsync
or ErrorCode.ERR_UnsafeOperation
or ErrorCode.ERR_UnsafeUninitializedStackAlloc
or ErrorCode.ERR_UnsafeMemberOperation
or ErrorCode.ERR_UnsafeMemberOperationCompat

or ErrorCode.Unknown
or ErrorCode.ERR_NoMetadataFile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private void EnsureAttributesExist(TypeCompilationState compilationState)
moduleBuilder.EnsureIsReadOnlyAttributeExists();
}

if (IsCallerUnsafe)
if (CallerUnsafeMode == CallerUnsafeMode.Explicit)
{
moduleBuilder.EnsureRequiresUnsafeAttributeExists();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public override bool IsExtern

internal sealed override bool HasUnscopedRefAttribute => false;

internal sealed override bool IsCallerUnsafe => false;
internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None;

internal override ObsoleteAttributeData ObsoleteAttributeData
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public override bool IsAbstract

internal sealed override bool HasUnscopedRefAttribute => false;

internal sealed override bool IsCallerUnsafe => false;
internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None;

internal sealed override ObsoleteAttributeData ObsoleteAttributeData
{
Expand Down
30 changes: 30 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/CallerUnsafeMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;

namespace Microsoft.CodeAnalysis.CSharp;

/// <summary>
/// Member safety under updated memory safety rules (<see cref="ModuleSymbol.UseUpdatedMemorySafetyRules"/>).
/// </summary>
internal enum CallerUnsafeMode
{
/// <summary>
/// The member is not considered unsafe under the updated memory safety rules.
/// </summary>
None,

/// <summary>
/// The member is implicitly considered unsafe because it contains pointers in its signature.
/// This member should not have the <see cref="AttributeDescription.RequiresUnsafeAttribute"/> emitted.
/// </summary>
Implicit,

/// <summary>
/// The member is explicitly marked as <see langword="unsafe"/> under the updated memory safety rules.
/// This member should have the <see cref="AttributeDescription.RequiresUnsafeAttribute"/> emitted.
/// </summary>
Explicit,
}
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ protected override bool HasSetsRequiredMembersImpl

internal sealed override bool UseUpdatedEscapeRules => false;

internal sealed override bool IsCallerUnsafe => false;
internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None;

internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol builderArgument)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public ErrorPropertySymbol(Symbol containingSymbol, TypeSymbol type, string name

internal sealed override bool HasUnscopedRefAttribute => false;

internal sealed override bool IsCallerUnsafe => false;
internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None;

internal sealed override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,9 @@ public override bool IsVararg
protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable();
internal sealed override bool HasUnscopedRefAttribute => false;

internal sealed override bool IsCallerUnsafe => false;
// The function pointer type itself is not unsafe under the new rules, only its invocation is.
// That is analogous to normal pointer types (and pointer dereference, respectively) under the new rules.
internal sealed override CallerUnsafeMode CallerUnsafeMode => CallerUnsafeMode.None;

internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? builderArgument)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,12 @@ internal static bool HasParameterContainingPointerType(this Symbol member)
}
}

if (member.TryGetInstanceExtensionParameter(out var extensionParameter) &&
extensionParameter.Type.ContainsPointerOrFunctionPointer())
{
return true;
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ public override ImmutableArray<CSharpAttributeData> GetAttributes()

bool isExtensionMethod = false;
bool isReadOnly = false;
bool requiresUnsafe = false;
bool hasRequiresUnsafeAttribute = false;
if (checkForExtension || checkForIsReadOnly || checkForRequiredMembers || isInstanceIncrementDecrementOrCompoundAssignmentOperator || isNewExtensionMember || checkForRequiresUnsafe)
{
attributeData = containingPEModuleSymbol.GetCustomAttributesForToken(_handle,
Expand All @@ -1057,7 +1057,7 @@ public override ImmutableArray<CSharpAttributeData> GetAttributes()

isExtensionMethod = !extensionAttribute.IsNil;
isReadOnly = !isReadOnlyAttribute.IsNil;
requiresUnsafe = !requiresUnsafeAttribute.IsNil;
hasRequiresUnsafeAttribute = !requiresUnsafeAttribute.IsNil;
}
else
{
Expand All @@ -1077,7 +1077,7 @@ public override ImmutableArray<CSharpAttributeData> GetAttributes()

if (!requiresUnsafeAlreadySet)
{
_packedFlags.InitializeRequiresUnsafe(requiresUnsafe);
_packedFlags.InitializeRequiresUnsafe(ComputeRequiresUnsafe(hasRequiresUnsafeAttribute));
}

// Store the result in uncommon fields only if it's not empty.
Expand Down Expand Up @@ -1481,14 +1481,14 @@ internal override bool IsDeclaredReadOnly
}
}

private bool IsDeclaredRequiresUnsafe
private bool RequiresUnsafe
{
get
{
if (!_packedFlags.RequiresUnsafePopulated)
{
bool requiresUnsafe = _containingType.ContainingPEModule.Module.HasAttribute(_handle, AttributeDescription.RequiresUnsafeAttribute);
_packedFlags.InitializeRequiresUnsafe(requiresUnsafe);
bool hasRequiresUnsafeAttribute = _containingType.ContainingPEModule.Module.HasAttribute(_handle, AttributeDescription.RequiresUnsafeAttribute);
_packedFlags.InitializeRequiresUnsafe(ComputeRequiresUnsafe(hasRequiresUnsafeAttribute));
}

return _packedFlags.RequiresUnsafe;
Expand Down Expand Up @@ -1816,7 +1816,28 @@ internal sealed override bool HasUnscopedRefAttribute

internal sealed override bool UseUpdatedEscapeRules => ContainingModule.UseUpdatedEscapeRules;

internal sealed override bool IsCallerUnsafe => ContainingModule.UseUpdatedMemorySafetyRules && IsDeclaredRequiresUnsafe;
private bool ComputeRequiresUnsafe(bool hasRequiresUnsafeAttribute)
{
return ContainingModule.UseUpdatedMemorySafetyRules
? hasRequiresUnsafeAttribute
// This might be expensive, so we cache it in _packedFlags.
: this.HasParameterContainingPointerType() || ReturnType.ContainsPointerOrFunctionPointer();
}

internal sealed override CallerUnsafeMode CallerUnsafeMode
{
get
{
if (!RequiresUnsafe)
{
return CallerUnsafeMode.None;
}

return ContainingModule.UseUpdatedMemorySafetyRules
? CallerUnsafeMode.Explicit
: CallerUnsafeMode.Implicit;
}
}

internal override bool HasAsyncMethodBuilderAttribute(out TypeSymbol builderArgument)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,22 +659,44 @@ internal sealed override bool HasUnscopedRefAttribute
}
}

private bool IsDeclaredRequiresUnsafe
private bool RequiresUnsafe
{
get
{
if (!_flags.TryGetRequiresUnsafe(out bool requiresUnsafe))
{
var containingPEModuleSymbol = (PEModuleSymbol)this.ContainingModule;
requiresUnsafe = containingPEModuleSymbol.Module.HasAttribute(_handle, AttributeDescription.RequiresUnsafeAttribute);
bool hasRequiresUnsafeAttribute = containingPEModuleSymbol.Module.HasAttribute(_handle, AttributeDescription.RequiresUnsafeAttribute);
requiresUnsafe = ComputeRequiresUnsafe(hasRequiresUnsafeAttribute);
_flags.SetRequiresUnsafe(requiresUnsafe);
}

return requiresUnsafe;
}
}

internal override bool IsCallerUnsafe => ContainingModule.UseUpdatedMemorySafetyRules && IsDeclaredRequiresUnsafe;
private bool ComputeRequiresUnsafe(bool hasRequiresUnsafeAttribute)
{
return ContainingModule.UseUpdatedMemorySafetyRules
? hasRequiresUnsafeAttribute
// This might be expensive, so we cache it in _packedFlags.
: this.HasParameterContainingPointerType() || Type.ContainsPointerOrFunctionPointer();
}

internal sealed override CallerUnsafeMode CallerUnsafeMode
{
get
{
if (!RequiresUnsafe)
{
return CallerUnsafeMode.None;
}

return ContainingModule.UseUpdatedMemorySafetyRules
? CallerUnsafeMode.Explicit
: CallerUnsafeMode.Implicit;
}
}

public override ImmutableArray<ParameterSymbol> Parameters
{
Expand Down Expand Up @@ -794,7 +816,7 @@ public override ImmutableArray<CSharpAttributeData> GetAttributes()

_flags.SetCustomAttributesPopulated();
_flags.SetHasRequiredMemberAttribute(!required.IsNil);
_flags.SetRequiresUnsafe(!requiresUnsafe.IsNil);
_flags.SetRequiresUnsafe(ComputeRequiresUnsafe(!requiresUnsafe.IsNil));
}

var uncommonFields = _uncommonFields;
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ public bool IsConditional

internal abstract bool UseUpdatedEscapeRules { get; }

internal abstract override bool IsCallerUnsafe { get; }
internal abstract override CallerUnsafeMode CallerUnsafeMode { get; }

/// <summary>
/// Some method kinds do not participate in overriding/hiding (e.g. constructors).
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public abstract MethodSymbol SetMethod

internal abstract bool HasUnscopedRefAttribute { get; }

internal abstract override bool IsCallerUnsafe { get; }
internal abstract override CallerUnsafeMode CallerUnsafeMode { get; }

/// <summary>
/// Returns the overridden property, or null.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ public override int GetHashCode()

internal sealed override bool HasUnscopedRefAttribute => false;

internal sealed override bool IsCallerUnsafe => throw ExceptionUtilities.Unreachable();
internal sealed override CallerUnsafeMode CallerUnsafeMode => throw ExceptionUtilities.Unreachable();

internal sealed override bool UseUpdatedEscapeRules => _reducedFrom.UseUpdatedEscapeRules;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ internal override bool IsMetadataFinal

internal sealed override bool UseUpdatedEscapeRules => true;

internal sealed override bool IsCallerUnsafe => throw ExceptionUtilities.Unreachable();
internal sealed override CallerUnsafeMode CallerUnsafeMode => throw ExceptionUtilities.Unreachable();

internal sealed override int TryGetOverloadResolutionPriority() => throw ExceptionUtilities.Unreachable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public SignatureOnlyPropertySymbol(

internal override int TryGetOverloadResolutionPriority() => throw ExceptionUtilities.Unreachable();

internal override bool IsCallerUnsafe => throw ExceptionUtilities.Unreachable();
internal override CallerUnsafeMode CallerUnsafeMode => throw ExceptionUtilities.Unreachable();

#endregion Not used by PropertySignatureComparer
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ internal override bool GenerateDebugInfo

internal override bool IsInitOnly => false;

internal override bool IsCallerUnsafe => false;
internal override bool IsUnsafe => false;

public override ImmutableArray<ImmutableArray<TypeWithAnnotations>> GetTypeParameterConstraintTypes() => ImmutableArray<ImmutableArray<TypeWithAnnotations>>.Empty;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,5 @@ internal sealed override TypeWithAnnotations IteratorElementTypeWithAnnotations
}

internal sealed override bool IsIterator => _lazyIteratorElementType is object;

/// <summary>
/// Whether the method has the <see langword="unsafe"/> keyword in its signature.
/// Do not confuse with <see cref="IsCallerUnsafe"/>.
/// </summary>
internal abstract bool IsUnsafe { get; }

internal sealed override bool IsCallerUnsafe => ContainingModule.UseUpdatedMemorySafetyRules && IsUnsafe;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo)
GetReturnTypeAttributes();

var compilation = DeclaringCompilation;
if (IsCallerUnsafe) compilation.EnsureRequiresUnsafeAttributeExists(addTo, GetFirstLocation(), modifyCompilation: false);
if (CallerUnsafeMode == CallerUnsafeMode.Explicit) compilation.EnsureRequiresUnsafeAttributeExists(addTo, GetFirstLocation(), modifyCompilation: false);
ParameterHelpers.EnsureRefKindAttributesExist(compilation, Parameters, addTo, modifyCompilation: false);
ParameterHelpers.EnsureParamCollectionAttributeExists(compilation, Parameters, addTo, modifyCompilation: false);
ParameterHelpers.EnsureNativeIntegerAttributeExists(compilation, Parameters, addTo, modifyCompilation: false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
compilation.EnsureIsReadOnlyAttributeExists(diagnostics, _location, modifyCompilation: true);
}

if (IsCallerUnsafe)
if (CallerUnsafeMode == CallerUnsafeMode.Explicit)
{
compilation.EnsureRequiresUnsafeAttributeExists(diagnostics, _location, modifyCompilation: true);
}
Expand Down
Loading
Loading