-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix SafeContext of Span-valued collection expressions to match specification #80684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ication Co-authored-by: RikkiGibson <5833655+RikkiGibson@users.noreply.github.com>
@copilot Please add a new file with path # Breaking changes in Roslyn after .NET 10.0.100 through .NET 11.0.100
This document lists known breaking changes in Roslyn after .NET 10 general release (.NET SDK version 10.0.100) through .NET 11 general release (.NET SDK version 11.0.100).
## The *safe-context* of a collection expression of Span/ReadOnlySpan type is now *declaration-block*
The C# compiler made a breaking change in order to properly adhere to the [ref safety rules](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#ref-safety) in the *collection expressions* feature specification. Specifically, the following clause:
> * If the target type is a *span type* `System.Span<T>` or `System.ReadOnlySpan<T>`, the safe-context of the collection expression is the *declaration-block*.
Previously, the compiler used safe-context *function-member* in this situation. We have now made a change to use *declaration-block* per the specification. This can cause new errors to appear in existing code, such as in the scenario below:
```cs
scoped Span<int> items1 = default;
scoped Span<int> items2 = default;
foreach (var x in new[] { 1, 2 })
{
Span<int> items = [x];
if (x == 1)
items1 = items; // previously allowed, now an error
if (x == 2)
items2 = items; // previously allowed, now an error
}
```
See also https://github.com/dotnet/csharplang/issues/9750.
|
Co-authored-by: RikkiGibson <5833655+RikkiGibson@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Looks good, but please address comment #80684 (comment).
The error we are fixing here is not a use after free error. It's not a memory safety issue. It is a correctness issue in which the contents of spans are aliased unexpectedly. |
|
Co-authored-by: 333fred <2371880+333fred@users.noreply.github.com>
... Added the breaking changes documentation file in commit 4d0ccc5.
Done. Added the breaking changes documentation in commit 4d0ccc5. |
|
||
## The *safe-context* of a collection expression of Span/ReadOnlySpan type is now *declaration-block* | ||
|
||
***Introduced in Visual Studio 2026 version 18.3*** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This version is not out yet, but, assuming we do not backport to 10.0.100, this is when we expect the fix to reach users.
Now working on building runtime with the change. |
@copilot Please add tests for the following scenarios, nearby to the other tests whose baselines were changed. using System;
class C
{
public C(scoped ReadOnlySpan<int> items)
{
int x = 0;
items = new ReadOnlySpan<int>(ref x); // error
}
void M(scoped ReadOnlySpan<int> items)
{
int x = 0;
items = new ReadOnlySpan<int>(ref x); // ok
}
} using System;
class C
{
public C(scoped ReadOnlySpan<int> items)
{
items = [0]; // error
}
void M(scoped ReadOnlySpan<int> items)
{
items = [0]; // ok
}
} The expectation is actually that both the constructor and ordinary method cases would permit this. Don't attempt to change the implementation to achieve the expected behavior yet. Just create the test methods, passing the source code for the scenarios into CreateCompilation, VerifyDiagnostics etc and paste in the resulting baselines in order to make the tests pass. |
Co-authored-by: RikkiGibson <5833655+RikkiGibson@users.noreply.github.com>
... Added the requested tests in commit 7e2f62f:
The baselines show that:
|
@copilot Add a test to CollectionExpressionTests.cs which is similar to This test might fail a debug assertion when it is run, which indicates there is real need for the Please resolve the issue by restoring the override from the original code, and adding a parameter Pass |
…ns (#120771) [Doc for upcoming breaking change](https://github.com/dotnet/roslyn/blob/copilot/fix-safecontext-of-span-collection/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2011.md#the-safe-context-of-a-collection-expression-of-spanreadonlyspan-type-is-now-declaration-block) See dotnet/roslyn#80684. TensorShape's constructor was the only break I found when compiling the libraries. I fixed this by extracting the collection-expression to the top level.
Fixes #80107
Fixes dotnet/csharplang#9750
Problem
Collection expressions with Span type were incorrectly using
SafeContext.CurrentMethod
for escape analysis, which allowed them to escape their declaring scope. This caused the following problematic code to compile without errors:The issue is that
items
is a collection expression created in the foreach loop body (a nested scope), but was being allowed to escape to the outer scope and be assigned toitems1
anditems2
. This is a correctness issue where the contents of spans are aliased unexpectedly.Additionally, there was a related issue where locals in the top-level block of constructors had an incorrect ref-safe-context, causing collection expressions and other constructs to incorrectly produce errors when assigned to scoped parameters in constructors.
Solution
Changed two locations in
Binder.ValueChecks.cs
:Line 4588 in
GetValEscape
: ChangedSafeContext.CurrentMethod
tolocalScopeDepth
Line 5336 in
CheckValEscape
: ChangedSafeContext.CurrentMethod
toescapeFrom
Fixed ref-safe-context of locals in the top-level block of constructors in
RefSafetyAnalysis.cs
:Breaking Change
This is an intentional breaking change to fix incorrect code patterns. After this change, the problematic code above now correctly produces compilation errors:
Documentation
docs/compilers/CSharp/Compiler Breaking Changes - DotNet 11.md
describing the change and providing workaroundsTest Updates
SpanAssignment_NestedScope_IssueExample
that validates the fix with the exact scenario from the issueSpanAssignment_ScopedParameter_Constructor_Span
andSpanAssignment_ScopedParameter_Constructor_CollectionExpression
to validate that scoped parameters in constructors work correctly (previously failed, now pass)Fixes #80683
Original prompt
Fixes #80683
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.