未验证 提交 5f4c7abe 编写于 作者: R Rikki Gibson 提交者: GitHub

Don't check safe-to-escape of receiver arguments to readonly members (#35597)

* Allow readonly methods to accept span parameters from stackalloc

* Cleanup

* Add relevant spec language to CheckInvocationArgMixing

* isReadOnlyInvocation -> isReceiverRefReadOnly

* Move isReceiverRefReadOnly to local function
上级 eb9aabb5
......@@ -1322,6 +1322,11 @@ bool isRefEscape
uint scopeOfTheContainingExpression,
DiagnosticBag diagnostics)
{
// SPEC:
// In a method invocation, the following constraints apply:
// - If there is a ref or out argument of a ref struct type (including the receiver), with safe-to-escape E1, then
// - no argument (including the receiver) may have a narrower safe-to-escape than E1.
if (symbol.IsStatic)
{
// ignore receiver when symbol is static
......@@ -1333,7 +1338,7 @@ bool isRefEscape
// collect all writeable ref-like arguments, including receiver
var receiverType = receiverOpt?.Type;
if (receiverType?.IsRefLikeType == true && receiverType?.IsReadOnly == false)
if (receiverType?.IsRefLikeType == true && !isReceiverRefReadOnly(symbol))
{
escapeTo = GetValEscape(receiverOpt, scopeOfTheContainingExpression);
}
......@@ -1432,6 +1437,17 @@ bool isRefEscape
}
return true;
static bool isReceiverRefReadOnly(Symbol methodOrPropertySymbol) => methodOrPropertySymbol switch
{
MethodSymbol m => m.IsEffectivelyReadOnly,
// TODO: val escape checks should be skipped for property accesses when
// we can determine the only accessors being called are readonly.
// For now we are pessimistic and check escape if any accessor is non-readonly.
// Tracking in https://github.com/dotnet/roslyn/issues/35606
PropertySymbol p => p.GetMethod?.IsEffectivelyReadOnly != false && p.SetMethod?.IsEffectivelyReadOnly != false,
_ => throw ExceptionUtilities.UnexpectedValue(methodOrPropertySymbol)
};
}
/// <summary>
......
......@@ -2466,6 +2466,181 @@ public void CopyTo(Span<T> other)
);
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyRefStruct_Method_RefLikeStructParameter()
{
var csharp = @"
using System;
public readonly ref struct S<T>
{
public void M(Span<T> x) { }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
b.M(x);
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyMethod_RefLikeStructParameter()
{
var csharp = @"
using System;
public ref struct S<T>
{
public readonly void M(Span<T> x) { }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
b.M(x);
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyRefStruct_RefLikeProperty()
{
var csharp = @"
using System;
public readonly ref struct S<T>
{
public Span<T> P { get => default; set {} }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
b.P = x;
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (11,15): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// b.P = x;
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(11, 15));
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyRefLikeProperty_01()
{
var csharp = @"
using System;
public ref struct S<T>
{
public readonly Span<T> P { get => default; set {} }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
b.P = x;
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (11,15): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// b.P = x;
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(11, 15));
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyRefLikeProperty_02()
{
var csharp = @"
using System;
public ref struct S<T>
{
public Span<T> P { get => default; readonly set {} }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
b.P = x;
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (11,15): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// b.P = x;
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(11, 15));
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyIndexer_RefLikeStructParameter_01()
{
var csharp = @"
using System;
public ref struct S<T>
{
public readonly Span<T> this[Span<T> span] { get => default; set {} }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
_ = b[x];
b[x] = x;
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (11,13): error CS8347: Cannot use a result of 'S<byte>.this[Span<byte>]' in this context because it may expose variables referenced by parameter 'span' outside of their declaration scope
// _ = b[x];
Diagnostic(ErrorCode.ERR_EscapeCall, "b[x]").WithArguments("S<byte>.this[System.Span<byte>]", "span").WithLocation(11, 13),
// (11,15): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// _ = b[x];
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(11, 15));
}
[Fact, WorkItem(35146, "https://github.com/dotnet/roslyn/issues/35146")]
public void ReadOnlyIndexer_RefLikeStructParameter_02()
{
var csharp = @"
using System;
public ref struct S<T>
{
public Span<T> this[Span<T> span] { get => default; readonly set {} }
public unsafe static void N(S<byte> b)
{
Span<byte> x = stackalloc byte[5];
_ = b[x];
b[x] = x;
}
}
";
var comp = CreateCompilationWithMscorlibAndSpan(csharp, TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (10,13): error CS8350: This combination of arguments to 'S<byte>.this[Span<byte>]' is disallowed because it may expose variables referenced by parameter 'span' outside of their declaration scope
// _ = b[x];
Diagnostic(ErrorCode.ERR_CallArgMixing, "b[x]").WithArguments("S<byte>.this[System.Span<byte>]", "span").WithLocation(10, 13),
// (10,15): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// _ = b[x];
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(10, 15),
// (11,9): error CS8350: This combination of arguments to 'S<byte>.this[Span<byte>]' is disallowed because it may expose variables referenced by parameter 'span' outside of their declaration scope
// b[x] = x;
Diagnostic(ErrorCode.ERR_CallArgMixing, "b[x]").WithArguments("S<byte>.this[System.Span<byte>]", "span").WithLocation(11, 9),
// (11,11): error CS8352: Cannot use local 'x' in this context because it may expose referenced variables outside of their declaration scope
// b[x] = x;
Diagnostic(ErrorCode.ERR_EscapeLocal, "x").WithArguments("x").WithLocation(11, 11));
}
[WorkItem(22197, "https://github.com/dotnet/roslyn/issues/22197")]
[Fact()]
public void RefTernaryMustMatchValEscapes()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册