Skip to content

stackalloc can initialize a ROS#1576

Open
BillWagner wants to merge 1 commit intodotnet:draft-v8from
BillWagner:stackalloc-ros
Open

stackalloc can initialize a ROS#1576
BillWagner wants to merge 1 commit intodotnet:draft-v8from
BillWagner:stackalloc-ros

Conversation

@BillWagner
Copy link
Member

The ReadOnlySpan<T> is also a valid type for a stackalloc in safe code.

Found while investigating #1232

While this doesn't address #1232, it was an omission.

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*:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this change is right.

  1. 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.

  2. 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
    }

Copy link
Contributor

@KalleOlaviNiemitalo KalleOlaviNiemitalo Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implicit conversion is required by C.3 Standard Library Types not defined in ISO/IEC 23271:

public readonly ref struct Span<T>
{
public int Length { get; }
public ref T this[int index] { get; }
public static implicit operator ReadOnlySpan<T>(Span<T> span);
}

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.

@BillWagner BillWagner added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

meeting: discuss This issue should be discussed at the next TC49-TG2 meeting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants