Skip to content
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

Remove constraints on stackalloc (support new locations) #1211

Merged
merged 6 commits into from
Dec 11, 2024

Conversation

gafter
Copy link
Member

@gafter gafter commented Nov 20, 2024

No description provided.

@gafter gafter added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Nov 20, 2024
@gafter gafter marked this pull request as ready for review November 20, 2024 18:27
@gafter gafter added this to the C# 8.0 milestone Nov 20, 2024
@gafter
Copy link
Member Author

gafter commented Nov 20, 2024

This change reflects the following behavior.

This is illegal:

    public void M() {
        var p = stackalloc nint[3];
    }

Because a stackalloc expression used as an initializer is of type T* (an unsafe pointer type) which requires an unsafe context. However, these are legal:

    public void M() {
        Span<nint> p = stackalloc nint[3];
    }

and

    public void M() {
        var p = (stackalloc nint[3]);
    }

(Note the addition of parens)

@gafter
Copy link
Member Author

gafter commented Nov 20, 2024

I don't understand the following behavior:

This is illegal:

    public void M() {
        var p = stackalloc nint[3][1];
    }

I don't understand why. Perhaps because `nint[3] is parsed as a type. I get the error

•	error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('nint[]')
•	error CS1575: A stackalloc expression requires [] after type

Yet this is legal:

    public void M() {
        var p = (stackalloc nint[3])[1];
    }

@gafter gafter changed the title Remove constraints on stackalloc Remove constraints on stackalloc (support new locations) Nov 20, 2024
@gafter gafter added the Review: pending Proposal is available for review label Nov 20, 2024
@jskeet
Copy link
Contributor

jskeet commented Dec 10, 2024

Is this intended to replace or be related to #604? I can't quite get my head round it all.

Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

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

I think this looks good. We should discuss the general comments.

standard/expressions.md Outdated Show resolved Hide resolved
standard/expressions.md Outdated Show resolved Hide resolved
@BillWagner
Copy link
Member

I don't understand the following behavior:

This is illegal:

    public void M() {
        var p = stackalloc nint[3][1];
    }

[...] Perhaps because `nint[3] is parsed as a type. I get the error

I think that's correct. It's trying to stackalloc an array of 1 where the element is nint[3], which is a managed type.

Yet this is legal:

    public void M() {
        var p = (stackalloc nint[3])[1];
    }

This surprises me as well. I think this should be illegal as well. According to sharplab, the type is ref IntPtr, which should be pointing to an array of elements. That would seem to mean the compiler took a reference to a managed type.

@KalleOlaviNiemitalo
Copy link
Contributor

var p = (stackalloc nint[3])[1];

Because this stackalloc nint[3] expression is not the entire initialiser, its type is Span<nint> rather than nint*. Then, the [1] index means calling the get accessor of the public ref T this[int index] { get; } indexer of Span<T>. The result of this call has type ref nint. Next, the referenced nint value should be loaded from that location, but the compiler emits this load only in the Debug configuration and optimises it out in Release, because it has no side effects. The C# decompiler used by SharpLab shows a local variable ref IntPtr reference being initialised with the returned ref nint, but that variable is not the var p of the source code. In the Debug configuration, the decompiler instead shows IntPtr intPtr.

standard/expressions.md Outdated Show resolved Hide resolved
@Nigel-Ecma
Copy link
Contributor

I don't understand the following behavior:

This is illegal:

    public void M() {
        var p = stackalloc nint[3][1];
    }

I don't understand why. Perhaps because `nint[3] is parsed as a type.

According to the v7 grammar it is not illegal and parses as an element_access of a stackalloc_expression. nint is an unmanaged_type, not a type, which excludes array types.

Note that the syntactically very similar new nint[3][1] is illegal as it was deemed confusing to allow it in the original C# design (and they syntactic method of making it illegal is the root of why the C# grammar isn’t “ANTLR ready” – but I digress ;-)). Maybe the compiler in question is approaching stackalloc as it does new and therefore declares it illegal?

The parenthesised version (stackalloc nint[3])[1] (and the similiar new) is also legal and parses exactly the same as the unparanethised version.

standard/unsafe-code.md Outdated Show resolved Hide resolved
gafter and others added 2 commits December 11, 2024 12:54
@BillWagner BillWagner merged commit f1dd653 into dotnet:draft-v8 Dec 11, 2024
6 checks passed
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 Review: pending Proposal is available for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants