Conversation
The `ReadOnlySpan<T>` is also a valid type for a `stackalloc` in safe code.
| Each *stackalloc_element_initializer* shall have an implicit conversion to *unmanaged_type* ([§10.2](conversions.md#102-implicit-conversions)). The *stackalloc_element_initializer*s initialize elements in the allocated memory in increasing order, starting with the element at index zero. In the absence of a *stackalloc_initializer*, the content of the newly allocated memory is undefined. | ||
|
|
||
| If a *stackalloc_expression* occurs directly as the initializing expression of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§24.3](unsafe-code.md#243-pointer-types)) or inferred (`var`), then the result of the *stackalloc_expression* is a pointer of type `T*` ([§24.9](unsafe-code.md#249-stack-allocation)). In this case the *stackalloc_expression* must appear in unsafe code. Otherwise the result of a *stackalloc_expression* is an instance of type `Span<T>`, where `T` is the *unmanaged_type*: | ||
| If a *stackalloc_expression* occurs directly as the initializing expression of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§24.3](unsafe-code.md#243-pointer-types)) or inferred (`var`), then the result of the *stackalloc_expression* is a pointer of type `T*` ([§24.9](unsafe-code.md#249-stack-allocation)). In this case the *stackalloc_expression* must appear in unsafe code. Otherwise the result of a *stackalloc_expression* is an instance of type `Span<T>` or `ReadOnlySpan<T>`, where `T` is the *unmanaged_type*: |
There was a problem hiding this comment.
I don't think this change is right.
-
Consider the following (SharpLab):
using System; public class C { public void M() { C c = stackalloc int[1]; } public static implicit operator C(Span<int> x) => new C(); }
If ReadOnlySpan<T> has a similar implicit conversion operator from Span<T>, then that can be used for the initialization, and the type of the stackalloc expression need not be ReadOnlySpan<T> directly.
-
If the type of stackalloc expression could be either Span<T> or ReadOnlySpan<T>, then you'd likely need a disambiguation rule for when both types are feasible, e.g. when calling an overloaded or generic method.
There was a problem hiding this comment.
I think @KalleOlaviNiemitalo is correct here, it looks like Span<T> has an implicit conversion to ReadOnlySpan<T>. If Span is changed to ReadOnlySpan in the example it fails as it requires two implicit conversions to be inserted, but use an intermediate variable and it is valid as each line only requires the insertion of one conversion:
public void M()
{
ReadOnlySpan<int> x = stackalloc int[1];
C c = x;
}There was a problem hiding this comment.
The implicit conversion is required by C.3 Standard Library Types not defined in ISO/IEC 23271:
csharpstandard/standard/standard-library.md
Lines 578 to 583 in a0995e5
So I don't think any normative text for stackalloc should be changed for this. A note could be added though.
C.3 seems to be the only mention of ReadOnlySpan<> in the spec. AFAICT the semantics of the implicit conversion are unspecified and a conforming implementation could make it always return default(ReadOnlySpan<T>). Users would be unlikely to choose such an implementation though. But any note added in the stackalloc description should be carefully written not to claim any semantics that the standard does not actually require.
The
ReadOnlySpan<T>is also a valid type for astackallocin safe code.Found while investigating #1232
While this doesn't address #1232, it was an omission.