Skip to content

More unsafe spec updates#9831

Merged
333fred merged 3 commits into
dotnet:mainfrom
333fred:unsafe-updates
Dec 5, 2025
Merged

More unsafe spec updates#9831
333fred merged 3 commits into
dotnet:mainfrom
333fred:unsafe-updates

Conversation

@333fred

@333fred 333fred commented Nov 19, 2025

Copy link
Copy Markdown
Member

Add a few more open questions and adjust the wording with decisions from the 12th.

@333fred 333fred requested a review from a team as a code owner November 19, 2025 22:31
Comment thread proposals/unsafe-evolution.md Outdated
@@ -136,7 +136,13 @@ it would be if any parameter were a by-`ref`, optional, or `params`.

It is a memory safety error convert a delegate type that is marked as `unsafe` to `System.Delegate`/`System.Linq.Expressions.Expression`/`System.Linq.Expressions.Expression<T>`.

@jkotas jkotas Nov 19, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this include object as well? Otherwise, one can do unsafe delegate -> object -> safe delegate.

What can one actually do with the unsafe delegates with all these limitations? #Resolved

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

What can one actually do with the unsafe delegates with all these limitations?

Pass them around and call them in an unsafe context. I don't know how much people are generally counting on converting them object or similar; I certainly don't use that functionality.

@jkotas jkotas Nov 20, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Right, pass them around on your little island. I do not expect libraries are generally going to have APIs that take unsafe delegate arguments.

To me, it feels like that the unsafe delegates are a mine field that will require a lot of special casing and provide very little value. Starting without them may be better.

Comment thread proposals/unsafe-evolution.md Outdated
### Delegate type `unsafe`ty

We could remove the ability to make delegate types as `unsafe` entirely, and simply require that all conversions of `unsafe` lambdas or method groups to a delegate type occur inside an `unsafe` context.
This could simplify the model around `unsafe` in C#, but at the risk of forcing `unsafe` annotations in the wrong spot and having an area where the real area of `unsafe`ty isn't properly called out.

@jkotas jkotas Nov 19, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we started without unsafe delegates, can they be added later as an incremental non-breaking change once/if proven necessary? #Resolved

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, I expect so.

it would be if any parameter were a by-`ref`, optional, or `params`.

It is a memory safety error convert a delegate type that is marked as `unsafe` to `System.Delegate`/`System.Linq.Expressions.Expression`/`System.Linq.Expressions.Expression<T>`.
It is a memory safety error convert a delegate type that is marked as `unsafe` to `System.Delegate`/`System.Linq.Expressions.Expression`/`System.Linq.Expressions.Expression<T>`, or any interface those

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does it mean that the unsafe delegates cannot be used as generic arguments (in safe contexts)?

If they can be used as generic arguments, one can do the offending memory unsafe cast indirectly by doing e..g.:

IEnumerable<UnsafeDelegate> e1 = ...!;

IEnumerable<Delegate> e2 = e1.Cast<Delegate>();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@333fred Let's capture this in open issues

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would it be better to postpone the whole unsafe delegate idea until we have evidence that it is actually worth it to deal with all the complex corner cases that it comes with?

Comment thread proposals/unsafe-evolution.md Outdated
> [!NOTE]
> We don't actually attribute the delegate type itself, just the `Invoke`, `BeginInvoke`, and `EndInvoke` methods. Determining whether a delegate type is `unsafe` is done by examining those 3 methods.
> If all are marked as `unsafe`, the delegate type is considered `unsafe`. If only some are marked as `unsafe`, then it is presumed that calling the others is safe and only calling the member that is
> marked as `unsafe` will cause a memory safety error. It will be a memory safety error to convert an `unsafe` lambda or method group to a delegate type that is does not have all of `Invoke`, `BeginInvoke`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
> marked as `unsafe` will cause a memory safety error. It will be a memory safety error to convert an `unsafe` lambda or method group to a delegate type that is does not have all of `Invoke`, `BeginInvoke`,
> marked as `unsafe` will cause a memory safety error. It will be a memory safety error to convert an `unsafe` lambda or method group to a delegate type that does not have all of `Invoke`, `BeginInvoke`,

member bodies of that type are considered an `unsafe` context. `unsafe` on a member will mean that that member is `unsafe`, and the body of that member is considered an `unsafe` context. For existing code
moving to the new definition of `unsafe`, this may produce a number of false positives for methods that don't need to be considered `unsafe`; we believe this better than false positives around not doing
this, or making it an error to put `unsafe` on a type which would easily be the largest breaking change that we've ever introduced in C#.
(except for iterator bodies). We propose changing this definition from textual to sematic. `unsafe` on a member will mean that that member is `unsafe`, and the body of that member is considered an `unsafe`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Regarding the syntactical meaning of unsafe on bodies, there is no change, right? So for example, iterators still escape out of the unsafe context.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

There's an open question on that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

There's an open question on that.

Comment thread proposals/unsafe-evolution.md Outdated

### Lambda/method group natural types

Today, the only real impact on codegen (besides additional metadata) is changing the *function_type* of a lambda or method group when `unsafe` is in the signature. If we were to avoid doing this, then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not impacting just codegen, it's impacting semantics too since different delegate types cannot be converted to each other, so for example this snippet will stop working:

unsafe void M() { }
var x = M;
System.Action y = x;

@jcouv jcouv self-assigned this Nov 24, 2025
@jjonescz

jjonescz commented Dec 4, 2025

Copy link
Copy Markdown
Member

@333fred can this be merged?

@333fred 333fred merged commit 80f7e03 into dotnet:main Dec 5, 2025
1 check passed
@333fred 333fred deleted the unsafe-updates branch December 5, 2025 22:18
jjonescz added a commit to dotnet/roslyn that referenced this pull request Jan 26, 2026
Test plan: #81207
OHI not handled as part of this PR.
Delegates handled according to this open question:
https://github.com/dotnet/csharplang/blob/79da45137622071d3c80ebe0a1296387af67afb9/proposals/unsafe-evolution.md#delegate-type-unsafety
(i.e., it's not possible to mark delegates as caller-unsafe - I'd expect
this to be approved and even if not, it seems like a good starting point
- see also comments by jkotas under
dotnet/csharplang#9831).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants